Compare commits

...

226 Commits

Author SHA1 Message Date
fc1f78e8cc Bump version to 3.14.3
Update NEWS.
2014-12-19 12:04:48 +01:00
25aa942a0e monitor-manager-xrandr: Set CRTC config even if it might be redundant
This optimization breaks our use of XRRScreenResources' timestamps to
detect hotplugs in case one of the outputs is disconnected and the
remaining ones don't need any mode, position or transform adjustments.

In that scenario, when applying the new configuration, we resize the X
screen but never call XRRSetCrtcConfig() and since XRRSetScreenSize()
doesn't take a timestamp and the X server doesn't update its last set
timestamp, when we next get a RRScreenChangeNotify and update
ourselves, XRRScreenResources.timestamp will still be smaller than
XRRScreenResources.configTimestamp which makes us think we're seeing a
new hotplug. We just don't enter an endless loop because the screen
size that we keep applying is always the same and the X server
short-circuits and stops sending us RRScreenChangeNotifys.

Always calling XRRSetCrtcConfig() ensures that the last set timestamp
will be bigger than configTimestamp in the next event and thus making
us trigger the monitors-changed signal properly.

Note that the X server already does basically the same checks that
we're removing here, so doing this shouldn't be a significant
efficiency loss. See

http://cgit.freedesktop.org/xorg/xserver/tree/randr/rrcrtc.c?h=server-1.16-branch#n539

https://bugzilla.gnome.org/show_bug.cgi?id=740838
2014-12-10 19:14:58 +01:00
56e74b1ea8 MetaWindowActor: don't overwrite send_frame_messages_timer
If the app finished multiple frames before we sent _NET_WM_FRAME_DRAWN,
we could add the send_frame_messages_timer multiple times. In the rare
case that the app immediately closed the window, the older timeout
could potentially then run on the freed actor.

https://bugzilla.gnome.org/show_bug.cgi?id=738686
2014-12-02 11:49:06 -05:00
7d3204b196 Fix problems resulting in left-over queued frames
* Use -1 rather than 0 as a flag for pending queue entries; 0 is
  a valid frame_counter value from Cogl.
* Consistently handle the fact we can have more than one pending
  entry. It's app misbehavior to submit a new frame before
  _NET_WM_FRAME_DRAWN is received; but we accept such frame messages,
  so we can't just leak them.
* If we remove send_frame_message_timer, assign the current frame counter
  to pending entries.
* To try to avoid regressing on this, when sending _NET_WM_FRAME_TIMINGS
  messages, if we have stale messages, or messages with no frame drawn
  time, warn and remove them from the queue rather than just accumulating.
* Improve commenting.

https://bugzilla.gnome.org/show_bug.cgi?id=738686
2014-12-02 11:49:01 -05:00
d7ff632c67 window-x11: Fix windows that set empty input shapes
Windows that set empty input shapes get n_rects of 0 when querying them
later, which makes sense, but the code that interpreted the result
translated it into a NULL input shape, which meant it was the same as
the bounding region. As such, an empty input shape would actually get
interpreted as a full input shape!

We, ourselves, set an empty input shape on tray icon windows in
gnome-shell since we would handle the picking ourselves. This meant that
we'd actually get the MetaSurfaceActorX11 when hovering over the tray
icon, instead of the ShellGTKEmbed that we capture events on and react
to.

This fixes weird tray icon behavior in gnome-shell.
2014-11-26 22:46:59 +01:00
6d3e64226d Revert "screen: Set a black background for testing purposes"
This reverts commit ec8ed1dbb0.

1) It turns out to add a momentary flicker from the transition
between the login screen and user session
2) It actually isn't needed anymore since bug 733026

https://bugzilla.gnome.org/show_bug.cgi?id=740377
2014-11-20 16:22:55 -05:00
2e7b9e0dfe window-actor: Do not request unredirection when destroyed
WindowActors can outlive their corresponding window to animate unmap.
Unredirecting the actor does not make sense in that case, so make
sure to not request it.

https://bugzilla.gnome.org/show_bug.cgi?id=740133
2014-11-14 18:31:02 +01:00
08d81b6f7f Bump version to 3.14.2
Update NEWS.
2014-11-12 19:00:56 +01:00
e01077914d configure: Actually make gbm optional
Whoops, I made the code work without it, but forgot to strip it from the
actual list of requires packages.

Spotted-by: Rico Tzschichholz <ricotz@ubuntu.com>
2014-11-10 14:54:31 +01:00
d7cf6bed63 Make gbm optional
Now it's only required by the native backend. The cursor code is getting
quite messy, but it was already considerable messy to start with.
2014-11-10 14:54:11 +01:00
d071ba8446 cursor: Clean up code flow slightly
Reverse the set of expressions so testing for gbm is at the top.
2014-11-10 14:53:19 +01:00
4d08e89c16 xrandr: ignore hotplug_mode_update value
The important thing is whether this property exists or not, but the value
doesn't matter.
2014-11-05 16:36:24 -06:00
21d8c4b032 monitor-manager: Don't try to match the outputs on hotplug
meta_monitor_config_match_current() only matches the number of outputs
and if the output connector, vendor, product and serial match.

This means that we can't use it to bypass doing any
work because it won't detect cases where we actually want to update
ourselves like e.g. an output being turned off either by us or by
another X client (e.g. xrandr).

https://bugzilla.gnome.org/show_bug.cgi?id=738630
2014-11-05 15:51:26 +01:00
c98686da92 monitor-config: Prevent a crash applying config for a closed lid
When a laptop's lid is closed we try to build and apply a temporary
configuration that disables the laptop's display if we have other
outputs.

This isn't enough though, we must also check if at least one of these
other outputs is enabled otherwise we'll try to resize the screen to
0x0 which (rightfully) hits an assertion.

https://bugzilla.gnome.org/show_bug.cgi?id=739450
2014-10-31 17:38:29 +01:00
a19eda5ae7 Bump version to 3.14.1.5
Update NEWS.
2014-10-30 11:01:04 +00:00
0a9bbe0109 meta-wayland-surface: Correcly scale the input region
The input region currently only gets scaled by the surface
scale while ignoring the output scale, which causes input events to not get
delivered correctly for clients on hidpi screens. So take the output scale
into account when doing so.

https://bugzilla.gnome.org/show_bug.cgi?id=739161
2014-10-27 18:13:00 +01:00
a8eb42e43c Revert "wayland-surface: Apply the surface scale only if needed"
This commit is wrong, it assumes that the scale only applies to the one
set by the client but its not. meta_surface_actor_wayland_scale_texture
also handles the output scale. Revert the commit to fix hidpi for wayland
clients like weston-terminal.

This reverts commit 0364ea9140.

https://bugzilla.gnome.org/show_bug.cgi?id=739161
2014-10-27 18:12:52 +01:00
9d0c9f1f42 Updated Slovak translation 2014-10-19 17:43:23 +00:00
9fa0743394 Remove unused variable 2014-10-16 11:00:51 +02:00
bb79a20fac display: Fix accidental inversion from 2f9c601
Commit 2f9c601 accidentally changed the logic here, changing the grab
behavior when not using raise-on-click. Fix this.

Spotted-by: Adam Goode <adam@spicenitz.org>
2014-10-15 23:54:20 +02:00
3e511b9591 Bump version to 3.14.1
Update NEWS.
2014-10-14 20:26:31 +02:00
5664c703b7 screen: Always consider monitors with fullscreen windows "in-fullscreen"
Fullscreen windows look weird when they are overlapped by system chrome,
which currently happens when another window is stacked above. We used to
auto-minimize fullscreen windows in that case, which proved to be both
unreliable and unpopular. So instead, keep the system chrome hidden even
when the fullscreen window is not stacked at the top.

https://bugzilla.gnome.org/show_bug.cgi?id=693991
2014-10-14 18:42:38 +02:00
5c80c4b006 window-x11: Update the input region after setting the client rect
We clip the input region to the client rect, so the client rect should
be up to date before we fetch the input region.

This fixes popup windows not working in GTK+2 under Wayland.

We should also update the shape / input regions when the window is
reconfigured for a complete fix, so that making an O-R window bigger
doesn't confuse mutter, but let's leave that to a future commit.
2014-10-12 16:14:17 -07:00
22f91eba8d backend: Fix minor comment 2014-10-12 13:41:03 -07:00
d07e2f4090 workspace: fix crash when creating a new workspace with sticky windows that have struts
The constructor would collect windows that are sticky before initializing its state
which would lead to a crash in the case of windows with struts which trigger a work
area recalculation where mutter would assume, due to uninitialized state, that an
existing work area has to be freed.

https://bugzilla.gnome.org/show_bug.cgi?id=738384
2014-10-12 22:27:02 +02:00
cd32e4a68a meta-surface-actor-x11: Fix unredirect heuristic
Damage coordinates are relative to the drawable not to the screen. So we
have to check whether x and y are 0 and not window_rect.x/y otherwise the
herustic will never trigger for windows on monitors whos x and y are not 0.

https://bugzilla.gnome.org/show_bug.cgi?id=738271
2014-10-12 00:35:47 +02:00
4040a70781 wayland-keyboard: Send modifiers after the key event
The key event should be interpreted by clients with the modifier state
as it was before the event itself just as in X11 input events.
Achieving this in wayland is a matter of sending the key event first
and the modifiers after (if needed).

This isn't really specified in the wayland protocol but it matches
weston's behavior and should avoid corner cases in clients.

https://bugzilla.gnome.org/show_bug.cgi?id=738238
2014-10-10 18:12:23 +02:00
cb084cc841 build: Require clutter-egl-1.0 for native backend only
https://bugzilla.gnome.org/show_bug.cgi?id=738225
2014-10-09 20:03:31 +02:00
2deea6e0a3 events: Fix build without wayland
https://bugzilla.gnome.org/show_bug.cgi?id=738225
2014-10-09 20:03:30 +02:00
a116509301 meta-surface-actor-x11: Detatch the pixmap in window_decorated_notify
The window can change its decoration without changing its size.

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

Found by Jasper St. Pierre <jstpierre@mecheye.net>
2014-10-08 23:11:47 +02:00
ead79f834c Revert "wayland-pointer: Just use the pointer actor instead of doing a full repick"
This reverts commit 33acb5fea0.

The issue here is that the pointer actor does not actually get reset
when the actor's reactivity changes, so we end up with stale picks after
actors are destroyed.

I have a local patch to Clutter for this, but I don't have time to
submit it upstream, so let's just use the ugly code for now.
2014-10-08 13:43:57 -07:00
7e431bd6bc Revert "pointer: Repick after the focused surface is destroyed"
This reverts commit e496ed50d6.

This was incorrect. wl_surface_destructor actually does the full repick
-- doing it here is dangerous, because the destroy listeners actually
run *before* the destructor, not after, so the surface is still alive.
2014-10-08 12:38:56 -07:00
272e1fb296 MetaBackgroundActor: queue a redraw when the background changes
When the MetaBackground changes, queue the actor for redraw.
2014-10-08 15:03:02 -04:00
c39f18c2d4 wayland-keyboard: Don't send pressed keys on enter
We never want to send pressed keys to wayland clients on enter. The
protocol says that we should send them, presumably so that clients can
trigger their own key repeat routine in case they are given focus and
a key is physically pressed.

Unfortunately this causes some clients, in particular Xwayland, to
register key events that they really shouldn't handle, e.g. on an
Alt+Tab keybinding, where Alt is released before Tab, clients would
see Tab being pressed on enter followed by a key release event for
Tab, meaning that Tab would be processed by the client when it really
shouldn't.

Since the use case for the pressed keys array on enter seems weak to
us, we'll just fake that there are no pressed keys instead which
should be spec compliant even if it might not be true.

https://bugzilla.gnome.org/show_bug.cgi?id=727178
2014-10-08 15:26:28 +02:00
33acb5fea0 wayland-pointer: Just use the pointer actor instead of doing a full repick
The full repick is unnecessary -- Clutter already does it for us.
2014-10-07 21:30:15 -07:00
591718dc02 wayland: Clump the globals code together 2014-10-07 20:54:28 -07:00
b6127eeda4 wayland: Remove old comments 2014-10-07 20:52:57 -07:00
eeff1b8b02 wayland: Remove unused variable 2014-10-07 20:51:18 -07:00
354cc466af wayland: Make WaylandEventSource private 2014-10-07 20:50:57 -07:00
9f5c38d121 wayland: Make the MetaWaylandRegion type opaque 2014-10-07 20:44:19 -07:00
ead0e902ed wayland: Move MetaWaylandRegion into a new file as well 2014-10-07 20:44:18 -07:00
5d16194b03 wayland: Clean up a bit more 2014-10-07 20:42:27 -07:00
a74acf0ec2 wayland: Clean up more includes 2014-10-07 20:42:27 -07:00
3044cfb7bf wayland-surface: Clean up includes 2014-10-07 20:42:27 -07:00
f658740043 wayland: Move some buffer manipulation functions to meta-wayland-buffer 2014-10-07 20:42:27 -07:00
c1613a16c0 wayland: Put the MetaWaylandBuffer implementation in a new file 2014-10-07 20:42:27 -07:00
8e85015f91 default: Adjust the default background
Getting a bit tired of green...
2014-10-07 20:42:26 -07:00
f127ee3bde wayland-surface: Fix a build coming from a bad rebase 2014-10-07 12:09:52 -07:00
acd928044f wayland-surface: Remove MetaWaylandSurfaceExtension
It only contained a pointer to a wl_resource, which isn't much of
value. Just replace it with the wl_resource instead. Any future private
data should be handled by our future role system.
2014-10-07 11:23:45 -07:00
4ef2f2ce09 wayland-surface: Remove create_surface_extension and friends
This function has a lot of parameters, and doesn't do much in the way of
boilerplate. It's a lot simpler to hand-code.
2014-10-07 11:23:45 -07:00
bc81736e6b wayland-surface: Rename the subsurface extension to wl_subsurface
To match the interface name.
2014-10-07 11:23:45 -07:00
49092397f2 wayland-surface: Group MetaWaylandSurface members logically
And add comments so that we know what's what. This cleans up the struct.
2014-10-07 11:23:45 -07:00
97705d3cfe wayland-surface: Move wl_surface.frame above role-specific stuff
The role-specific stuff will soon be part of a set_role callback set on
the surface itself.
2014-10-07 11:23:44 -07:00
0364ea9140 wayland-surface: Apply the surface scale only if needed
There's no need to call scale_texture on every commit.
2014-10-07 11:23:31 -07:00
c0bdb3018b display: Do not include unmanaging windows in list_windows()
There's a small window before a window that is being unmanaged is
unregistered with the display. The MetaScreen::window-left-monitor
and MetaWorkspace::window-removed emissions fall right into that
window, so code that runs in that time may well be out of our
control; we can make sure that the method it can use to get an
updated list of windows no longer contains the destroyed window
though, which is a much better option than expecting everyone to
filter the list themselves.
2014-10-07 20:09:09 +02:00
924eaac358 Updated Latvian translation 2014-10-07 20:42:42 +03:00
a9f5a5661f Updated Latvian translation 2014-10-07 20:40:14 +03:00
9c589b6798 wayland: Ensure drag surface offset changes update the DnD actor 2014-10-06 19:39:43 -07:00
113be01ce8 wayland: Use a MetaDnDActor for the DnD icon surface
The actor is updated on DnD grab motion events, properly notified
when dragging finishes, and destroyed if the client/surface disappear
below its feet.
2014-10-06 19:39:43 -07:00
28e59c5a8f compositor: Add MetaDnDActor
This actor is a subclass of MetaFeedbackActor that additionally
implements the "drag failed" animation, snapping back to the drag
origin position in a surface.
2014-10-06 19:39:43 -07:00
b588baf9f5 compositor: Add MetaFeedbackActor
This actor is a non-reactive container that autoembeds itself into
the feedback window group in the compositor. The API is meant to
help on creating things attached to pointer/touchpoints, with an
X/Y attachment offset, and following the position of certain events.
2014-10-06 19:39:43 -07:00
9a825d9bee compositor: Add a "feedback" window group
Although not strictly a window group... This ClutterActor is
meant to stay always on top, and only show non-reactive actors
created by Mutter itself. Two possible usecases for this layer
are DnD surfaces, and touch spots.

We might also want to move cursors out of an overlay in MetaStage
into here at some point.
2014-10-06 19:39:43 -07:00
f211b3ec90 wayland: Store whether the wl_data_source has a target selected
It will be useful to check whether DnD is going to fail or not.
2014-10-06 19:39:43 -07:00
0510c3a621 wayland: Keep track of the origin surface and drag point on DnD
Keeping track of the surface will be necessary in case it is destroyed
during DnD, and the coordinates will be useful when figuring out the
snap back coordinates.
2014-10-06 19:39:43 -07:00
18db5d0799 data-device: Store the current drag grab
And bail out if any further start_drag() is attempted.
2014-10-06 19:39:42 -07:00
c061e26da5 wayland: Record the offset position
This is needed for DND surfaces. We should probably test to see if it's
used for cursor surfaces at all.
2014-10-06 19:39:42 -07:00
166668adc4 window: Remove duplicate case value 2014-10-06 19:39:38 -07:00
ec797b055d window: Mark all override-redirect window types as appears-focused 2014-10-06 19:30:12 -07:00
082cc9c83a wayland: Immediately give keyboard focus to Wayland popups 2014-10-06 17:05:23 -07:00
993bec37d7 window: Ensure that popup window types propagate their focus appearance
In Wayland, popup window types are not override-redirect, and thus can
steal window focus away from their parent window when clicked on.

This means that we need to make sure their appearance is properly
propagated to the parent windows so the parent windows don't lose their
focus while they're propagated.
2014-10-06 17:01:08 -07:00
e496ed50d6 pointer: Repick after the focused surface is destroyed
Having a null focus is incorrect -- we want to pick the surface that's
under the new pointer position.
2014-10-06 16:30:09 -07:00
a127d05790 pointer: Make sure to update the focus after ending a grab
Otherwise, we might not reset it after the grab has ended.
2014-10-06 16:19:30 -07:00
607730e96c pointer: Fix the behavior of the pointer under DND
When grabbing with DND, we need to leave the pointer alone and
under the client's control. The code here was a bit messy before about
when it unset the window cursor -- it did it whenever there was no
current surface after repicking, which is a bit wrong, since it will
fire during a drag grab.

Move the check for this to update_cursor_surface, which is our standard
"sync" API for this, and then call update_cursor_surface after we set
the focus.
2014-10-06 15:48:42 -07:00
9203db0655 pointer: Don't fizzle out surface changes too soon
During a DND grab, pointer->focus_surface is NULL, since the wl_pointer
doesn't have any focused surface (it's in drag mode). In this case, the
drag interface has control of the focus, and when dragging into a NULL
surface, drag_grab_focus won't get called, properly detaching it from
the previous surface.

Let the interface->focus implementation do the fizzling out.

In the future, we should split out wl_pointer's implementation
(pointer->focus_surface) from the Wayland side of the generic pointer
wrapper (pointer->current) and use our event routing system to determine
or similar whether it should go to wl_pointer or wl_data_device.
2014-10-06 14:31:16 -07:00
64d40792c4 Updated Italian translation 2014-10-05 13:41:57 +00:00
e7356917b0 meta-monitor-manager-xrandr: Simplify handle_xevent
The code here was a bit messy with the addition of
hotplug_mode_update, and the comments were a bit confusing and
inaccurate. Clean it up and comment it a bit better to make the flow and
intention more clear.
2014-10-03 15:12:00 -06:00
fa58752276 backend-native: Handle keyboard repeat settings
We need to tell clutter's evdev backend about the desktop's key repeat
settings so that our own key bindings event processing and
gnome-shell's chrome widgets get their fake key events for continuous
key press as they expect.

Note that the wayland frontend filters out these events and thus
wayland clients do not see them as specced.

https://bugzilla.gnome.org/show_bug.cgi?id=728055
2014-10-03 18:31:44 +02:00
478b75e803 backend-x11: Re-upload keymap when new keyboard devices are added
The X server applies a default keymap to hotplugged keyboard
devices. To enforce our current settings we must re-upload the keymap
when a new keyboard shows up.

Note that setting the VCK keymap causes the server to propagate it
to all slave keyboard devices.

https://bugzilla.gnome.org/show_bug.cgi?id=737673
2014-10-02 19:14:03 +02:00
492a1b244f Revert "display: Don't put minimized windows at the back of alt-tab"
This reverts commit 7e61ef0936.

https://bugzilla.gnome.org/show_bug.cgi?id=705177
2014-10-01 17:29:15 -06:00
5d8ff2e34d screen: Remove auto-minimization "feature"
https://bugzilla.gnome.org/show_bug.cgi?id=705177
2014-10-01 17:29:02 -06:00
310083aeb2 keybindings: Remove special-case code for reversing automatically
Since we now directly expose the reverses bindings directly, we
don't have to have this special-case in do_choose_window.

More importantly, if the backwards binding is pressed and has the Shift
key included, this will actually revert it

This doesn't matter for Alt-Tab in gnome-shell, which already replaces
it with a better Alt-Tab replacement, but it does matter for Alt-Esc,
which switches between windows directly.
2014-10-01 16:51:45 -06:00
0faa900207 frames: Make sure to initialize button_state
Otherwise, we're comparing with uninitialized memory. Spotted by
valgrind.
2014-09-30 15:16:07 -06:00
b735571688 MetaBackgroundImage: free the GdkPixbuf after creating a texture
The GdkPixbuf used to load a texture was never freed.
2014-09-29 21:32:48 -04:00
5e249ad5eb prefs: Don't leak the variant value for unknown properties 2014-09-29 17:54:20 -06:00
21bffe4aef monitor-manager-xrandr: Fix small leak for invalid properties
If the property is invalid, then we leak the allocated buffer. Make sure
to free it in this case.
2014-09-29 17:54:20 -06:00
68283df4d9 workspace: Don't relocate sticky windows
Windows are relocated before their workspace is removed, however this
is only necessary for windows that are *only* on that workspace; for
windows on all workspaces, that step is annoying as it will unset the
sticky state requested by the user.

https://bugzilla.gnome.org/show_bug.cgi?id=737625
2014-09-30 00:41:25 +02:00
4f3de2ce39 workspace: Correctly initialize MRU list
The workspace MRU lists are updated when windows are managed/unmanaged
or change workspaces. However those updates obviously only apply to
existing workspaces - new workspaces will always start out with an empty
MRU list, despite sticky windows already being "on" that workspace.
As we now assert that the list contains all windows located on the
workspace, we need to initialize it correctly to avoid a crash.

https://bugzilla.gnome.org/show_bug.cgi?id=737581
2014-09-30 00:24:14 +02:00
9f8b641472 display: Optionally sort window list
https://bugzilla.gnome.org/show_bug.cgi?id=737581
2014-09-30 00:24:14 +02:00
a9a21c801c configure: Require gbm >= 10.3
Needed for 488dd0b402
2014-09-29 23:13:59 +02:00
482a97466d window: Fix typo 2014-09-27 07:41:10 +02:00
4e14bb9df3 window: Fix corner case in set_demands_attention()
We only grant requests to set the demands-attention hint if the window
is at least partially obscured; so for non-minimized windows on the
active workspace, we check if any other window on the same workspace
that is higher in the stack overlaps.
However in the case of a sticky window, window->workspace is NULL, so
we end up considering any non-sticky window on a different workspace.

At this point we have already established that the window is showing
on the active workspace, so use that to filter for windows that may
overlap.
2014-09-27 06:43:16 +02:00
df90545258 window: Fix crash when mapping sticky window
Since the introduction of set_workspace_state(), window->workspace
will always be NULL when on_all_workspaces is set - passing that
to a workspace function that does not validate its input will then
result in a crash.
Use the get_workspace() function instead, which will always return
a valid workspace.
2014-09-27 06:41:35 +02:00
c954f9cc24 workspace: Fix typo in META_IS_WORKSPACE macro 2014-09-27 06:37:38 +02:00
d06b39d13c window: Fix another case of uninitialized workspace state
Since commit 2eec11b445, windows without a __NET_WM_DESKTOP property
that should be on all workspaces are not added to the active workspace;
this is correct, however not adding them to any workspace is not ...
2014-09-26 11:48:11 +01:00
f3595ebd08 monitor-manager: Make sure to emit PropertiesChanged for PowerSaveMode
We overrode the property for PowerSaveMode, which meant that gdbus's
auto-generated PropertiesChanged code wasn't being run.

This really confused gnome-rr and gnome-settings-daemon's power plugin
about the current DPMS state of the display, since they used their
cached PowerSaveMode properties, and never saw a PropertiesChanged being
emitted.

If a display was on, they set it to off, and then set it back on, the
setting back on would never fire, since they thought the display was
already off.

To fix this, remove our custom property override and just respond to
notifications on the object.

Namely, this fixes the DPMS management when receiving notifications so
that it now properly times out.
2014-09-25 20:17:53 -06:00
1e1ca47ec1 window: Always set workspace state while constructing
set_workspace_state () returns early when the desired sticky state
and workspace match the current property values, assuming that the
corresponding MRU lists are already correct in that case.
However that might not be the case when we are setting the initial
state, so don't take the shortcut in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=737178
2014-09-25 15:16:09 +01:00
2eec11b445 window: Be more careful when setting initial workspace state
A window may either be sticky because it has been requested as such,
or because it is placed on a non-primary monitor (and the corresponding
preference is set). While we do take the latter into account, we
currently override the sticky state later during initialization;
be a bit more careful there to get the initial state right.

https://bugzilla.gnome.org/show_bug.cgi?id=737178
2014-09-25 15:16:09 +01:00
8ff4597201 Updated Bengali (India) translation 2014-09-25 08:26:38 +00:00
d5f2468d88 Updated Bulgarian translation 2014-09-25 06:28:04 +03:00
488dd0b402 Support for hardware cursor sizes other than 64x64 on wayland
Use the new DRM capabilities to figure out the correct cursor size, and
make sure that matches instead of hardcoding 64x64. This fixes incorrect
rendering on some newer AMD cards that support 256x256 cursors.

Based heavily on a patch by:
Alvaro Fernando García <alvarofernandogarcia@gmail.com>
2014-09-24 15:42:17 -06:00
6565bca210 wayland: Send accurate capabilities
mutter now knows whether the app menu should be shown, so expose this
properly under Wayland as well.
2014-09-24 15:42:17 -06:00
60c22b6236 keybindings: Do a breadth first search in our keysym to keycode code
Commit 1af0033368 made a subtle change
regarding how XKeysymToKeycode behaves. It does a depth first search
while XKeysymToKeycode is documented to do a breadth first search:

"this function looks in each column of the core keyboard mapping in
turn and returns the lowest numbered key that matches in the lowest
numbered group" - from the XKB library documentation

Looping over all keycodes for each layout and level index makes us go
back to the previous behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=737134
2014-09-24 23:20:42 +02:00
d3111a9f07 Fix stacking of the guard window
With the change to how hidden windows are stacked, the position
of the guard window with respect to the hidden windows got flipped
and the guard window was at the bottom of everything; fix it to
be on top of the hidden windows.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:51:20 -04:00
cdfb301200 Add a test for stacking vs. minimization
Test that the guard window is in the right place.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:51:20 -04:00
371560c2b6 tests: Add minimize/unminimize commands
Add commands to request the client to minimize or unminimize the window;
unminimize doesn't currently work for GTK+ because it expects XMapRequest
to be received by the window manager, but the window is already mapped.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:26:17 -04:00
7616881afa test-runner: represent the guard window as '|' for assert_stacking
Allow putting '|' into the list of windows for assert_stacking to
represent the position of the guard window. Not present is the same
as at the beginning (bottom) of the list.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:26:17 -04:00
74c37d49c4 test-runner: make test_case_wait() wait for queued-work
Sometimes (for example with minimization) a request from the client
causes queued work rather than immediate work; so make the test client
'wait' command wait for a full frame cycle.

https://bugzilla.gnome.org/show_bug.cgi?id=737233
2014-09-24 16:26:17 -04:00
d3142b92f0 Updated Serbian translation 2014-09-24 11:10:30 +02:00
ae2afa7c5e Updated Telugu translation 2014-09-23 14:48:16 +00:00
4a71621fbc keybindings: Fix indentation 2014-09-22 22:01:37 +02:00
565b9d73d5 keybindings: Do not depend on linux headers for above-tab key
Commit 2f229c3928 removed the code to compute the above-tab
keycode and replaced it with a simple constant from linux/input.h.
We obviously cannot depend on linux headers on non-linux systems,
so provide a fallback definition in that case (which is expected
to work assuming the system is using the Xorg xf86-input-keyboard
driver).

https://bugzilla.gnome.org/show_bug.cgi?id=737135
2014-09-22 21:54:48 +02:00
90bd02ff4d constraints: Fix update_onscreen_requirements()
Another missing translation into screen coordinates ...

https://bugzilla.gnome.org/show_bug.cgi?id=736915
2014-09-22 20:12:08 +02:00
73ca0efaeb window: Fix titlebar_is_onscreen() test
The titlebar rect is in window coordinates, while screen regions are
obviously not. Fix by translating into screen coordinates before
testing for overlaps.

https://bugzilla.gnome.org/show_bug.cgi?id=736915
2014-09-22 20:12:08 +02:00
790269db95 Bump version to 3.14.0
Update NEWS.
2014-09-22 20:12:08 +02:00
cb82bd8afa Updated Hindi translation 2014-09-22 13:23:07 +00:00
b1e06ed110 Update Czech translation 2014-09-22 15:02:04 +02:00
fabe66e65f Updated Kannada translation 2014-09-22 05:14:51 +00:00
4a965a37d1 Updated German translation 2014-09-21 19:20:16 +00:00
302ff7b95a update zh_CN translation 2014-09-21 10:15:01 +08:00
e2e241340c Updated Danish translation 2014-09-20 17:22:51 +02:00
461aea47dd window: Adjust the frame rect when _GTK_FRAME_EXTENTS is set on map 2014-09-19 17:35:38 -06:00
d87093fe29 window: Don't queue move/resizes if the extents are the same
GTK+ sets the frame extents on every allocation, so don't bother doing
any extra work if things are the same.
2014-09-19 17:35:38 -06:00
0cde7879d6 window: Move set_custom_frame_extents to be X11-only
Wayland doesn't use custom frame extents anymore -- it uses a full
geometry description.
2014-09-19 17:35:38 -06:00
89ffcee7ca Fix computation of window positions for StaticGravity
When adjust_for_gravity() was simplified (01b6445708), the correct
handling of StaticGravity dropped out - fix adjust_for_gravity() to do
nothing in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=736719
2014-09-19 15:41:22 -04:00
1250afef7b Revert "window-x11: Fix the coordinates we use in the synthetic ConfigureNotify"
The coordinates in ConfigureNotify *should* be the coordinates of the
client window; using the coordinates of the frame window compensated for
a problem with the interpretation of StaticGravity for some clients but
broke other clients.

This reverts commit f4f70afe31.

https://bugzilla.gnome.org/show_bug.cgi?id=736719
2014-09-19 15:41:22 -04:00
3a577edaa7 Updated German translation 2014-09-18 21:55:42 +00:00
48dfde2073 keyboard/pointer: Calculate the serial once per event
Some applications, like totem, create keyboard/pointer objects from the
same client, and expect it to work. We made this work a while ago, but
due to an oversight in the code, we increment the serial on button press
for every resource that we need to send events to.

Since operations like move/resize use the grab serial of the devices to
determine whether the operation is exact, we need to make sure the same
serial goes to all devices.

Restructure the code so that all that's in the resource loop is the
sending of the event -- all the calculation that's needed happens
outside.

This fixes moving / resizing the Totem window not working sometimes.

https://bugzilla.gnome.org/show_bug.cgi?id=736840
2014-09-18 09:15:13 -06:00
4a41d415f8 wayland: Fix the placement of popup windows
The fix in d61dde1 regressed the position of popup windows, since the
size was 0x0 when we wanted to do a sole move. Only fizzle out in the
path where we actually *do* resize.

https://bugzilla.gnome.org/show_bug.cgi?id=736812
2014-09-17 17:42:37 +02:00
1fb7ca398d Updated Oriya translation 2014-09-17 11:27:43 +00:00
2b79935fd8 Updated Slovak translation 2014-09-17 09:10:51 +00:00
e3c915350e Updated Bengali (India) translation 2014-09-17 06:30:41 +00:00
2e06a6765c Bump version to 3.13.92
Update NEWS.
2014-09-17 06:14:24 +02:00
b63291069d docs: Allow building without wayland 2014-09-17 05:37:54 +02:00
f10cb02cbf prefs: Show fallback app menu based on XSetting
Going through GSD's settings was done in context of patches that
did not land; it is simpler and more consistent with GTK+ to use
the corresponding XSetting instead.
2014-09-17 05:37:53 +02:00
276df8f18d keyboard/pointer: Make sure to move focused resources into the list
We only broadcast input to the focus_resource_list, so we need to make
sure it's put in the proper list on startup.

This fixes input not working for windows when they first appear.

Argh. There's always more stuff to fix with keyboard/pointer. Every
single time I think I've fixed it, more stuff pops up.
2014-09-16 21:25:26 -06:00
d61dde12cb window-wayland: Don't send 1x1 sizes to GTK+ windows
GTK+ requests get_xdg_surface before attaching a buffer, and since it
might take a long time for GTK+ to get around to attaching a buffer and
committing it, our idle for MOVE_RESIZE will kick in beforehand.

And our idle will try to resize the 0x0 window that currently exists,
constrain it to 1x1, which will send a configure event of 1x1 to the
window while it boots up, causing it to awkwardly resize to the minimum
size of the window.

Make sure that in this case, our idle doesn't cause any problems, and
that we fizzle out any idles like this.

The "proper" way to do this would be to delay the creation of the
MetaWindow until a surface is committed, but that's difficult for a
variety of reasons, and might cause unintended issues with focus.
2014-09-16 21:14:19 -06:00
c8cc4344f2 events: Only process Enter/Leave events when in the normal route
This prevents issues from happening when processing Enter/Leave events
while in another kind of grab op like a Wayland popup or resizing a
window.

This can't ever really happen except outside of a race condition,
with the X server, since we won't ever pass input events to the
X server in any of these cases, but it can't hurt to be more correct
about what the intended operation is.
2014-09-16 20:31:13 -06:00
ae292c856b events: Ignore normal FocusIn events on the root window
GTK+ focuses its own windows with RevertToParent, which means that when
a GTK+ CSD window is destroyed, the X server will set the focus back to
the root window. The event stream that we is an UnmapNotify followed by
a FocusOut event. Our own UnmapNotify-handling code unmanages the window
and forcibly changes the focus to the next default window in the stack.

Since UnmapNotify events don't come with timestamps, we query for one,
and set the window focus using that.

But there's *still* a FocusOut event in the stack, with an older
timestamp and serial than our own focusing. We see this, throw it out
since it's older than the most recent focus, but then our own code that
notices the root has been focused kicks in and tries to focus the
default window... using a timestamp older than our most recent focusing.

meta_display_sanity_check_timestamps notices this, and (rightly so)
puts a warning in our face, telling something is awry.

Only let our workarounds kick in when the event is new enough, otherwise
our code will get confused over old events.

This stops the:

Window manager warning: last_focus_time (367917173) is greater than comparison timestamp (367917170).  This most likely represents a buggy client sending inaccurate timestamps in messages such as _NET_ACTIVE_WINDOW.  Trying to work around...

warning spam when closing a CSD window.
2014-09-16 20:25:51 -06:00
35dd1e644d events: Remove our workarounds for broken libXi versions
We now depend on a recent enough libXi that fixes broken locking in
XIGrabTouchBegin, so we don't need to carry this around anymore.
2014-09-16 20:10:59 -06:00
be85ead2f8 events: Fix a typo preventing the None detection from working properly
XINotifyDetailNone is a value for detail, not for mode.
2014-09-16 19:53:33 -06:00
5c40345128 window-wayland: Don't bother checking if anything changed
This is a small fixup. We don't need the check here, since we don't do
anything extra if it actually changed.
2014-09-16 19:16:38 -06:00
43b3573c51 window-wayland: Always update the last_sent size
The last_sent size is effectively what size we should send in configure
requests where the size hasn't changed. Thus, if an app commits a new
size, we need to make sure we respect it and don't reconfigure it with
a size it wasn't expecting when the state changes.

This fixes apps being sent a configure event with 0, 0 on startup,
which was confusing Clutter into displaying a 0x0 viewport.
2014-09-16 19:11:56 -06:00
ac6ec168da pointer: Make coding style similar to keyboard 2014-09-16 18:55:49 -06:00
dbb7b9e85b events: Remove an overzealous ifdef 2014-09-16 18:55:46 -06:00
1de740955f wayland: Don't leak the existing texture if we already have one
We were missing a check in ensure_buffer_texture that checked if we
already had a CoglTexture bound for the buffer.
2014-09-16 12:12:21 -06:00
21f123c69f Don't restack windows while we are unmanaging them
Restacking the frame for a window while unmanaging the window is
harmless, but for undecorated (in particular, client-side-decorated)
windows, this causes problems because the window is typically
destroyed by the client immediately after withredrawing the window.

Skip windows flagged as being unmanaged when assembling the new
stack and when comparing the old order to the new stack.

Add a stacking test for this.
2014-09-16 13:44:42 -04:00
d6624b0a75 Cleanup xwayland/wayland window association from the "unmanage" signal
Windows can be freed at some point after they are unmanaged - because
there is an effect in progress, because a language binding is holding
a reference. Therefore, we need to clean up the later to associate
the xwayland and wayland windows deterministically in an "unamanaged"
handler.

https://bugzilla.gnome.org/show_bug.cgi?id=736694
2014-09-16 10:59:45 -04:00
9c465a2d5a Do xwayland/wayland window association in a later, not an idle
g_idle_add() makes no guarantee about when it will be run - if Mutter
is busy drawing and blocking glXSwapBuffers() it could happen only
minutes later.  Use meta_later_add (META_LATER_BEFORE_REDRAW) instead -
this will deterministically be run after the Wayland socket is read
from but before the next frame is painted.

https://bugzilla.gnome.org/show_bug.cgi?id=736694
2014-09-16 10:59:45 -04:00
e53456d87c mutter-test-runner: Make criticals and warnings failures
Tests should not be counted as successful if Mutter is spewing
warnings - hook to the log handler so that we can catch that.
2014-09-16 10:59:45 -04:00
5716fc4b90 test-runner: Add 'csd' keyword for window creation
Allow specifying 'csd' when creating a window to make the client
create a client-side-decorated window.
2014-09-16 10:59:45 -04:00
e926ebafdb Updated Swedish translation 2014-09-15 15:34:10 +00:00
7125b801f2 Makefile-tests: Our test framework requires Wayland 2014-09-15 09:11:38 -06:00
d20dae3553 prefs: Don't listen to the cursor-size key
It will only confuse the code if somebody changes
it. gnome-settings-daemon already listens to this, so just use that.
2014-09-14 23:26:06 -06:00
73a47cec2a [l10n] Updated Catalan (Valencian) translation 2014-09-14 22:15:28 +02:00
514d3b4bde [l10n] Update Catalan translation 2014-09-14 22:15:28 +02:00
6910ab5389 Updated Tamil translation 2014-09-14 19:53:05 +00:00
4052b0f048 Updated Marathi translations 2014-09-14 21:17:19 +05:30
493c0f71d2 prefs: Update cursor size based on xsettings
We shouldn't scale the cursor size in mutter we g-s-d exports
the correct size on hidpi so use gtk-cursor-theme-size.

This way we also catch changes on resolution updates.

https://bugzilla.gnome.org/show_bug.cgi?id=729337
2014-09-14 10:21:46 +02:00
ab40dfdd51 Revert "prefs: Scale the root window cursor by the scale factor"
This reverts commit 4fe66ce0a9.

This is wrong ... we should not scale the cursor size but read
the cursor xsettings that gets exported by gsd. Also this won't update on
resolution changes.

https://bugzilla.gnome.org/show_bug.cgi?id=729337
2014-09-14 10:21:46 +02:00
52678c39e6 update Punjabi Translation - back for 3.14 2014-09-13 21:58:41 -05:00
a676249c0c stack-tracker: Fix an off-by-one error in restack_managed
When restacking the last window alone, we would trigger this off-by-one
error. This would throw us off the end of the array, causing lower_below
warnings for nonsensical values.

Since the last window already is lowered below everything else, we
shouldn't need to lower it.
2014-09-12 17:10:34 -06:00
2833c702c6 stack-tracker: Make lower_below / raise_above internal as well
These are unused elsewhere.
2014-09-12 16:56:27 -06:00
611f6741c2 windows-x11.c: Fix leaked error trap
The merge of the commit af46ef3b 'meta_window_new: clean up error handling'
to the wayland branch accidentally added an extra call to meta_error_trap_push(),
meaning that we leaked one level of error traps for each new window.

Fixes warning:
  Gdk-WARNING **: XSetErrorHandler() called with a GDK error trap pushed.

https://bugzilla.gnome.org/show_bug.cgi?id=736589
2014-09-12 17:28:53 -04:00
df2587a61c Don't pass configure events on the composite overlay window to MetaStackTracker
When the screen resizes, we get a configure event for the composite overlay
window - don't pass that to MetaStackTracker, since the COW isn't in the
stack.

Fixes warning:
 mutter-WARNING **: STACK_OP_RAISE_ABOVE: window 0x65 not in stack
2014-09-12 16:37:20 -04:00
30e7044746 display: Refix return value of set_alarm_filter 2014-09-12 15:12:09 -04:00
458953268b MetaBackground: fix getting stuck in a bad state after monitor changes
After the ::monitors-changed signal, set the dirty flag on each new
monitor information struct so the per-monitor resources will be
recreated.
2014-09-12 14:59:20 -04:00
1c227baf81 display: Fix return value of set_alarm_filter 2014-09-12 12:55:07 -06:00
892699da73 edid: Remove unused declarations 2014-09-12 11:55:08 -06:00
f163a15b13 MetaStackTracker: optimize out unnecessary X restacking
We have a quite accurate view of the X stack, so there's no good reason to ask
the X server to do restacking that has no effect. (Restackings that have no
effect on either X windows or Wayland windows were generally optimized out in
the synchronization code, but in other cases like moving an X window that is
only beneath Wayland windows to the top of the stack we would make such
requests.)

Removing such requests:
 - Is a small efficiency win in itself
 - Allows us to immediately go ahead and apply Wayland changes to the verified stack
 - Prevents queued Wayland changes piling up waiting for an X event that will never
   be received, since the X server will not send confirmation of no-op restacks.

Since such operations may still have an effect on the relative stacking of X
and Wayland windows, we need to continue applying them to the local stack.

https://bugzilla.gnome.org/show_bug.cgi?id=736559
2014-09-12 13:42:56 -04:00
87779ed34e MetaStackTracker: make functions used only internally static
Now that all actual stack shuffle is handled inside stack-tracker.c, we can make
meta_stack_tracker_record_[raise_above/lower_below] internal to that file and
remove the unused meta_stack_tracker_record_lower().

https://bugzilla.gnome.org/show_bug.cgi?id=736559
2014-09-12 13:42:56 -04:00
04bc846ef3 Move logic for syncing the stack to the X server into MetaStackTracker
stack.c:sync_stack_to_xserver had both code for assembling the desired stack, and
code for enforcing the desired stack on the actual stack of X and Wayland windows;
the latter part is properly the domain of stack-tracker.c; moving the code to
apply the stack there both simplifies it and keeps stack.c more manageable.

https://bugzilla.gnome.org/show_bug.cgi?id=736559
2014-09-12 13:42:56 -04:00
301acac163 stack.c: remove obsolete handling of override-redirect windows
There was still code in stack.c to handle skipping override-redirect windows,
but since quite a while ago, meta_stack_add() is not called for OR windows
since they are outside our stacking control. Add an assertion and remove
unnecessary code.

https://bugzilla.gnome.org/show_bug.cgi?id=736559
2014-09-12 13:42:56 -04:00
9401196e88 Remove cache of last stacking order in stack.c
stack.c kept it's own record of the last stacking it requested, so that
restacking could be done with minimal moves, but we already have a better
view of the stacking order with the stack tracker, so use that instead.

This allows eliminating the special case for the first restack.

https://bugzilla.gnome.org/show_bug.cgi?id=736559
2014-09-12 13:42:56 -04:00
3457366066 Move manipulation of the X stack to MetaStackTracker
Since MetaStackTracker is the code that knows about the current X stacking order
and the relationship between X windows and Wayland windows, it's cleaner to
encapsulate stack manipulation in MetaStackTracker rather than have the calling
code make the X calls and only call into MetaStackTracker to inform it about
the changes.

https://bugzilla.gnome.org/show_bug.cgi?id=736559
2014-09-12 13:42:56 -04:00
cb66cf6398 MetaStackTracker: eliminate the resynchronization process
The step where we requery the stacking order from the server than combine
it in an arbitrary fashion with Wayland windows can be eliminated by observing
that we are the final authority for Wayland window stacking - so if we
apply each X event that we receive from the X server to our stack in a
way that leaves the X windows ordered in the same way as on the server,
and apply events that we have stored locally in a way that doesn't affect
the ordering of X windows, than we have a fully correct ordering of windows.

Ordering this in the order of first applying the X event and then applying the
local portion also means that as long as we had an up-to-date view of the X
stack the composite operation will be identical to what was requested.

https://bugzilla.gnome.org/show_bug.cgi?id=736559
2014-09-12 13:42:56 -04:00
73573a85de Replace MetaStackWindow with a 64-bit "stack ID"
Putting X windows and pointers to MetaWindows into a union had a number of
problems:

 - It caused awkward initialization and conditionalization
 - There was no way to refer to Wayland windows (represented by
   MetaWindow *) in the past, which is necessary for the MetaStackTracker
   algorithms
 - We never even cleaned up old MetaStackWindow so there could be
   records in MetaStackWindow pointing to freed MetaWindow.

Replace MetaStackWindow with a 64-bit "stack ID" which is:

 - The XID for X Windows
 - a "window stamp" for Wayland windows - window stamps are assigned
   for all MetaWindow and are unique across the life of the process.

https://bugzilla.gnome.org/show_bug.cgi?id=736559
2014-09-12 13:42:56 -04:00
b49a4ae0bc Add missing file from test framework
mutter-all.test.in was accidentally not committed.
2014-09-12 13:40:33 -04:00
2f63c39fa6 Add a test framework and stacking tests
Add a basic framework for tests of Mutter handling of client behavior;
mutter-test-runner is a Mutter-based compositor that forks off instances
of mutter-test-client and sends commands to them based on scripts.
The scripts also include assertions.

mutter-test-runner always runs in nested-Wayland mode since the separate
copy of Xwayland is helpful in giving a reliably clean X server to
test against.

Initially the commands and assertions are designed to test the stacking
behavior of Mutter, but the framework should be extensible to test other
parts of client behavior like focus.

The tests are installed according to:

https://wiki.gnome.org/Initiatives/GnomeGoals/InstalledTests

if --enable-installed-tests is passed to configure. You can run them
uninstalled with:

 cd src && make run-tests

(Not in 'make check' to avoid breaking 'make distcheck' if Mutter can't be
run nested.)

https://bugzilla.gnome.org/show_bug.cgi?id=736505
2014-09-12 13:14:51 -04:00
95d9a95b2b Add meta_ui_window_is_dummy()
For reasons related to interaction between the GTK+ CSS code and the
frame sync protocol, the dummy GtkWindow that MetaUI creates to track
theme properties has to be mapped and have MetaWindow associated with it.
Add a private function so that the test framework can filter this out.

https://bugzilla.gnome.org/show_bug.cgi?id=736505
2014-09-12 11:00:55 -04:00
44ecb1c050 Add meta_display_set_alarm_filter()
Add a private hook for the test framework to get XSyncAlarmEvent events -
this will be used to implement XSyncCounter based synchronization
so that the test framework can deterministically wait until Mutter
has seen actions performed by an X11 client.

https://bugzilla.gnome.org/show_bug.cgi?id=736505
2014-09-12 11:00:55 -04:00
0706de5378 Add meta_wayland_get_[x]wayland_display_name
Add private functions for the test framework to use to find out the
wayland and x11 display names, so they can set up the environment for
children.

https://bugzilla.gnome.org/show_bug.cgi?id=736505
2014-09-12 11:00:55 -04:00
9dd9938c38 Remove obsolete mutter-test script
mutter-test was a script that was used to run various test on the
Metacity source tree (build with different options, etc.) This likely
hasn't been run once since the Metacity/Mutter branch point; remove
it to avoid confusion with the new test framework in src/tests.

https://bugzilla.gnome.org/show_bug.cgi?id=736505
2014-09-12 11:00:55 -04:00
e27bbdc769 Fix colors for horizontal background gradients
COGL_PIXEL_FORMAT_RGB_888 is packed 3-bytes per pixel.
2014-09-12 11:00:55 -04:00
09b46029fa Fix multi-monitor backgrounds
The texture area was meant to be in monitor-relative coordinates, but that
was not consistently followed throughout the code - fix.

https://bugzilla.gnome.org/show_bug.cgi?id=736568
2014-09-12 11:00:55 -04:00
5c289b7eab Updated gujarati translations 2014-09-12 11:50:14 +05:30
656573c5d2 wayland-keyboard: Handle keymap-layout-group-changed signal
We need to send a modifiers event to wayland clients when the layout
group changes.

https://bugzilla.gnome.org/show_bug.cgi?id=736433
2014-09-11 19:05:53 +02:00
59c5ac0cb5 backends: Add a keymap-layout-group-changed signal
We'll need this in the wayland frontend to send a modifiers event to
clients.

Note that on X11 this isn't needed because key events include the
group index encoded in modifier state. If we ever want to make the
wayland frontend work with the X11 backend we'll handle it then.

https://bugzilla.gnome.org/show_bug.cgi?id=736433
2014-09-11 19:05:53 +02:00
53092424e6 wayland-keyboard: Handle keymap-changed signal
We need to inform wayland clients of new keymaps.

https://bugzilla.gnome.org/show_bug.cgi?id=736433
2014-09-11 19:05:53 +02:00
6ba0491adf keybindings: Freeze and ungrab the keyboard only on X11 backend
This isn't needed in the native backend because we control all the
input event flow there.

https://bugzilla.gnome.org/show_bug.cgi?id=736433
2014-09-11 19:05:53 +02:00
e3fb9e4cee Updated Hungarian translation 2014-09-11 16:21:32 +00:00
8d53ae894b window-actor: Skip frame-sync when the corresponding window is gone
https://bugzilla.gnome.org/show_bug.cgi?id=735927
2014-09-11 16:50:23 +01:00
d50f8afa9e window-actor: Consider needs_destroy in is_destroyed()
According to the documentation, the method returns "whether the X window
that the actor was displaying has been destroyed" - that is very much
true when we delay the actual actor destruction for a destroy animation,
so update the method accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=735927
2014-09-11 16:50:23 +01:00
98fa343588 window-actor: Keep in compositor's window list until destroyed
When a window is destroyed, the corresponding actor may still be
kept around for the destroy effect. But as the actor is removed
from the compositor's stack list immediately, the compositor will
always stack it above "valid" window actors - this is not what we
want, so only update the compositor's list when the actor is
actually destroyed.

https://bugzilla.gnome.org/show_bug.cgi?id=735927
2014-09-11 16:50:23 +01:00
9ceb3fbb9a Updated Lithuanian translation 2014-09-10 20:22:58 +03:00
22d95546a7 Updated Russian translation 2014-09-09 16:58:50 +04:00
33689ec558 Moving setting of window-scaling-factor to meta_clutter_init()
Setting the scaling factor immediately after calling clutter_init()
avoids creating the stage at one size, then later resizing it to
a different size.

https://bugzilla.gnome.org/show_bug.cgi?id=736279
2014-09-08 14:40:50 -04:00
602dd7fdf2 MetaBackendX11: Don't XResizeWindow behind clutter's back
In the case of a nested Wayland compositor inside an X session,
Clutter is managing the toplevel window size, so don't call
XResizeWindow on it - this will confuse Clutter and get the size
and the hints out of sync on the toplevel window.

https://bugzilla.gnome.org/show_bug.cgi?id=736279
2014-09-08 14:40:50 -04:00
7f15c995b7 Finnish translation update by Jiri Grönroos 2014-09-07 13:44:39 +03:00
9be3e56b70 background: Fix monitor validation in get_texture()
Monitor indexes should be in the range [0, n], not [-1, 0] :-)
2014-09-06 18:22:56 +02:00
24119b8a9c Updated Norwegian bokmål translation. 2014-09-06 14:13:15 +02:00
4d75de006c wayland: Don't set_focus when the device has been released
It's possible for a released pointer to have repick / set_focus on it as
part of sync_input_focus. When the pointer is actually re-init'd, it
will memset 0, which can cause corruption as our destroy listener has
already been added.

Released devices should be idempotent, so just make sure method calls on
them don't have any effect.
2014-09-05 18:05:44 -07:00
e19516ec5a wayland: Don't set_focus for new resources
Otherwise, we can re-add the destroy listener, which can cause
corruption.

Instead, split out the broadcast function, and use that.
2014-09-05 17:58:15 -07:00
1ed607f398 wayland-surface: Make bad xdg-shell versions crash the client
Otherwise, we might continue with weird semantics.
2014-09-05 16:21:43 -07:00
7e0822c5b1 background-actor: Add missing paren 2014-09-05 13:51:21 -07:00
037c3438a3 meta-monitor-config: Fix small whitespace issue 2014-09-05 09:50:37 -07:00
cde5d4acfa Updated Korean translation 2014-09-05 06:28:38 +09:00
d79db68bf8 workspace: Clean up code style 2014-09-04 13:55:51 -07:00
b3b9d9e161 stack: Never focus unmanaging windows
We can enter weird states where get_default_window is called during
window unmanagement, before the window has been fully removed from
the stack. Make sure these windows are *never* returned from
get_default_window, as focusing them can cause an assertion fail,
or worse.
2014-09-04 13:53:06 -07:00
3f1f1645c7 backend: Fix build
I keep forgetting to squash.
2014-09-04 13:19:13 -07:00
18a82688e2 backend: Create the core device monitor
Otherwise, nothing will ever create it.
2014-09-04 13:15:03 -07:00
27d6b2645e meta-backend: Fix the max device calculation on removal
If we add device 2, then add device 254, then remove device 254, then
the max device ID will be 253. Scan through all the devices again on
removal to calculate a new max device ID.
2014-09-04 12:17:15 -07:00
fee40353e2 meta-backend: Fix build 2014-09-04 12:15:50 -07:00
659360d543 backend: Pre-emptively create idle monitors based on clutter events
Rather than have the DBus code control this, move this into
MetaBackend. This also lets us destroy idle monitors when appropriate,
rather than leaking them forever.
2014-09-04 12:06:03 -07:00
3ea6424b8f background: Fix meta_background_new
This is used by the default plugin.
2014-09-03 19:55:15 -07:00
96bee8e60d Conditionalize some more Wayland support 2014-09-03 19:51:02 -07:00
883c4a7b0f background-actor: Add a simple paint volume
Not having a paint volume causes every single paint to turn into
full-stage redraw, since otherwise culling won't properly work.

Since we don't paint outside of our allocation, just use the simple
default implementation, but also return TRUE inside it.
2014-09-03 11:08:48 -07:00
d4317ba1e4 background: Fix build
These warnings weren't properly working on Owen's machine, so they went
unchecked.
2014-09-03 11:03:17 -07:00
9d69b2a963 MetaBackground: add properties to set vignette settings
Make the vignette options properties so they can be animated;
modify the function-call API for meta_background_actor_set_vignette()
to correspond more closely to the 3 properties.

https://bugzilla.gnome.org/show_bug.cgi?id=735637
2014-09-03 13:43:40 -04:00
ef3b000050 MetaBackgroundActor: match total dimming if GLSL is not present
Without GLSL, we didn't apply the vignetting, which not only made the
background uniform in color, it made it much lighter. Adjust for this
and make the average brightness with the vignette effect the same
with or without GLSL.

https://bugzilla.gnome.org/show_bug.cgi?id=735637
2014-09-03 13:43:40 -04:00
a4a688ed83 Rewrite background code
The old requirement that multiple MetaBackgroundActor objects be
layered on top of each to produce blended backgrounds resulted in
extremely inefficient drawing since the entire framebuffer had
to be read and written multiple times.

 * Replace the MetaBackground ClutterContent with a plain GObject
   that serves to hold the background parameters and prerender
   textures to be used to draw the background. It handles
   colors, gradients, and blended images, but does not handle
   vignetting

 * Add vignetting to MetaBackgroundActor directly.

 * Add MetaBackgroundImage and MetaBackgroundImageCache to allow
   multiple MetaBackground objects to share the same images

By removing the usage of ClutterContent, the following optimizations
were easy to add:

 Blending is turned off when the actor is fully opaque
 Nearest-neighbour filtering is used when drawing 1:1

The GLSL vignette code is slightly improved to use a vertex shader
snippet for computing the texture coordinate => position in actor
mapping.

https://bugzilla.gnome.org/show_bug.cgi?id=735637
2014-09-03 13:43:40 -04:00
17dc5c57dd Use meta_actor_painting_untransformed() for MetaShapedTexture
The old check for using NEAREST by checking clutter_actor_is_in_clone_paint()
and meta_actor_is_untransformed (actor) doesn't work properly since
clutter_actor_is_in_clone_paint() does not look at ancestors of the
actor; it only applies to a direct clone of the actor. Using
meta_actor_painting_untransformed() allows us to check exactly what we
care about rather than using tricky approximations.

https://bugzilla.gnome.org/show_bug.cgi?id=735632
2014-09-03 13:43:40 -04:00
ef5f939db8 Factor out meta_actor_painting_untransformed()
The painting_untransformed() function in MetaWindowGroup is useful
elsewhere, in particular if we want to check whether we can avoid
bilinear filtering when painting a texture 1:1.

https://bugzilla.gnome.org/show_bug.cgi?id=735632
2014-09-03 13:43:40 -04:00
cb4751da4c Updated Polish translation 2014-09-03 16:02:48 +02:00
0685f17f73 Updated Indonesian translation 2014-09-03 13:56:49 +00:00
4b260d5d9f Bump version to 3.13.91
Update NEWS
2014-09-03 14:03:45 +02:00
c8f015c6d7 keybindings: Ignore extra modifier bits when matching iso_next_group
Clutter events include the layout index codified into modifier_state,
unlike XI2 device events, which means that we need to mask it out so
that we can match successfully.
2014-09-02 18:11:31 +02:00
122 changed files with 24884 additions and 26644 deletions

3
.gitignore vendored
View File

@ -44,6 +44,9 @@ po/*.pot
libmutter.pc
mutter
mutter-restart-helper
mutter-test-client
mutter-test-runner
mutter-all.test
org.gnome.mutter.gschema.valid
org.gnome.mutter.gschema.xml
org.gnome.mutter.wayland.gschema.valid

102
NEWS
View File

@ -1,3 +1,105 @@
3.14.3
======
* Fix crash when trying to unredirect a destroyed window [Florian; #740133]
* Fix "flicker" during startup transition [Ray; #740377]
* Don't leave left-over frames queued [Owen; #738686]
* Set CRTC configuration even if it might be redundant [Rui; #740838]
Contributors:
Rui Matos, Florian Müllner, Jasper St. Pierre, Ray Strode, Owen W. Taylor
3.14.2
======
* Prevent crash applying monitor config for a closed lid [Rui; #739450]
* Misc. fixes [Rui, Jonathon, Jasper; #738630]
Contributors:
Jonathon Jongsma, Rui Matos, Jasper St. Pierre
3.14.1.5
========
* Fix wayland hiDPI regressions [Adel; #739161]
Contributors:
Adel Gadllah, Florian Müllner, Jasper St. Pierre
Translations:
Dušan Kazik [sk]
3.14.1
======
* Fix move-titlebar-onscreen function [Florian; #736915]
* Fix stacking of the guard window [Owen; #737233]
* Fix keycode lookup for non-default layouts [Rui; #737134]
* Fix workspaces-only-on-primary handling [Florian; #737178]
* Don't unstick sticky windows on workspace removal [Florian; #737625]
* Do not auto-minimize fullscreen windows [Jasper; #705177]
* Upload keymap to newly added keyboard devices [Rui; #737673]
* Apply keyboard repeat settings [Rui; #728055]
* Don't send pressed keys on enter [Rui; #727178]
* Fix build without wayland/native [Rico; #738225]
* Send modifiers after the key event [Rui; #738238]
* Fix unredirect heuristic [Adel; #738271]
* Do not show system chrome over fullscreen windows [Florian; #693991]
* Misc. bug fixes [Florian, Adel, Tom; #737135, #737581, #738146, #738384]
Contributors:
Tom Beckmann, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner,
Jasper St. Pierre, Rico Tzschichholz, Owen W. Taylor
Translations:
Krishnababu Krothapalli [te], Мирослав Николић [sr, sr@latin],
Alexander Shopov [bg], Saibal Ray [bn_IN], Milo Casagrande [it],
Rūdolfs Mazurs [lv]
3.14.0
======
* Fix placement of popup windows on wayland [Jasper; #736812]
* Only increment serial once per event [Jasper; #736840]
* Fix window positioning regression with non-GTK+ toolkits [Owen; #736719]
Contributors:
Jasper St. Pierre, Owen W. Taylor
Translations:
Saibal Ray [bn_IN], Dušan Kazik [sk], Manoj Kumar Giri [or],
Christian Kirbach [de], Ask H. Larsen [da], YunQiang Su [zh_CN],
Bernd Homuth [de], Shankar Prasad [kn], Petr Kovar [cs], Rajesh Ranjan [hi]
3.13.92
=======
* Rewrite background code [Owen; #735637, #736568]
* Fix size in nested mode [Owen; #736279]
* Fix destroy animation of background windows [Florian; #735927]
* Wire keymap changes up to the wayland frontend [Rui; #736433]
* Add a test framework and stacking tests [Owen; #736505]
* Simplify handling of the merged X and wayland stack [Owen; #736559]
* Fix cursor size on HiDPI [Adel; #729337]
* Misc. bug fixes [Owen; #735632, #736589, #736694]
Contributors:
Adel Gadllah, Rui Matos, Florian Müllner, Jasper St. Pierre, Owen W. Taylor
Translations:
Andika Triwidada [id], Piotr Drąg [pl], Changwoo Ryu [ko],
Kjartan Maraas [nb], Ville-Pekka Vainio [fi], Yuri Myasoedov [ru],
Aurimas Černius [lt], Balázs Úr [hu], Sweta Kothari [gu], A S Alam [pa],
Sandeep Sheshrao Shedmake [mr], Shantha kumar [ta], Gil Forcada [ca],
Carles Ferrando [ca@valencia], Mattias Eriksson [sv]
3.13.91
=======
* Misc. bug fixes [Carlos; #735452]
Contributors:
Adel Gadllah, Carlos Garnacho, Rui Matos, Jasper St. Pierre,
Rico Tzschichholz
Translations:
Chao-Hsiung Liao po/zh_HK, zh_TW.po, Enrico Nicoletto [pt_BR],
Kjartan Maraas [nb], Fran Diéguez [gl], Yosef Or Boczko [he],
Maria Mavridou [el], Claude Paroz [fr]
3.13.90
=======
* Only call XSync() once per frame [Rui; #728464]

View File

@ -1,8 +1,8 @@
AC_PREREQ(2.62)
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [13])
m4_define([mutter_micro_version], [90])
m4_define([mutter_minor_version], [14])
m4_define([mutter_micro_version], [3])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@ -77,9 +77,7 @@ MUTTER_PC_MODULES="
cairo >= 1.10.0
gsettings-desktop-schemas >= 3.7.3
$CLUTTER_PACKAGE >= 1.19.5
clutter-egl-1.0
cogl-1.0 >= 1.17.1
gbm
upower-glib >= 0.99.0
gnome-desktop-3.0
xcomposite >= 0.2
@ -127,6 +125,12 @@ AC_ARG_WITH([xwayland-path],
[XWAYLAND_PATH="$withval"],
[XWAYLAND_PATH="$bindir/Xwayland"])
AC_ARG_ENABLE(installed_tests,
AS_HELP_STRING([--enable-installed-tests],
[Install test programs (default: no)]),,
[enable_installed_tests=no])
AM_CONDITIONAL(BUILDOPT_INSTALL_TESTS, test x$enable_installed_tests = xyes)
## here we get the flags we'll actually use
# Unconditionally use this dir to avoid a circular dep with gnomecc
@ -196,7 +200,7 @@ AC_SUBST(XWAYLAND_PATH)
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [libdrm libsystemd libinput], [have_native_backend=yes], [have_native_backend=no])
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [clutter-egl-1.0 libdrm libsystemd libinput gbm >= 10.3], [have_native_backend=yes], [have_native_backend=no])
if test $have_native_backend = yes; then
AC_DEFINE([HAVE_NATIVE_BACKEND],[1],[Define if you want to enable the native (KMS) backend based on systemd])
fi

View File

@ -111,6 +111,13 @@ IGNORE_HFILES= \
xprops.h \
$(NULL)
if !HAVE_WAYLAND
IGNORE_HFILES += \
meta-surface-actor-wayland.h \
wayland \
$(NULL)
endif
MKDB_OPTIONS+=--ignore-files="$(IGNORE_HFILES)"
# Images to copy into HTML directory.

1503
po/bg.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1068
po/ca.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1284
po/cs.po

File diff suppressed because it is too large Load Diff

1298
po/da.po

File diff suppressed because it is too large Load Diff

1530
po/de.po

File diff suppressed because it is too large Load Diff

176
po/fi.po
View File

@ -7,15 +7,15 @@
# Gnome 2012-03 Finnish translation sprint participants:
# Pauli Virtanen <pauli.virtanen@hut.fi>, 2003-2005.
# Tommi Vainikainen <thv@iki.fi>, 2011.
# Jiri Grönroos <jiri.gronroos+l10n@iki.fi>, 2012, 2013.
# Jiri Grönroos <jiri.gronroos+l10n@iki.fi>, 2012, 2013, 2014.
#
msgid ""
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: 2014-08-08 21:51+0000\n"
"PO-Revision-Date: 2013-09-06 22:23+0300\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?"
"product=mutter&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2014-09-06 21:56+0000\n"
"PO-Revision-Date: 2014-09-07 12:25+0300\n"
"Last-Translator: Jiri Grönroos <jiri.gronroos+l10n@iki.fi>\n"
"Language-Team: suomi <gnome-fi-laatu@lists.sourceforge.net>\n"
"Language: fi\n"
@ -47,10 +47,9 @@ msgid "Move window to workspace 4"
msgstr "Siirrä ikkuna työtilaan 4"
#: ../data/50-mutter-navigation.xml.in.h:6
#, fuzzy
#| msgid "Move window to workspace 1"
msgid "Move window to last workspace"
msgstr "Siirrä ikkuna työtilaan 1"
msgstr "Siirrä ikkuna viimeiseen työtilaan"
#: ../data/50-mutter-navigation.xml.in.h:7
msgid "Move window one workspace to the left"
@ -69,98 +68,128 @@ msgid "Move window one workspace down"
msgstr "Siirrä ikkunaa yksi työtila alas"
#: ../data/50-mutter-navigation.xml.in.h:11
#, fuzzy
#| msgid "Move window one workspace to the left"
msgid "Move window one monitor to the left"
msgstr "Siirrä ikkunaa yksi työtila vasemmalle"
msgstr "Siirrä ikkuna yhden näytön verran vasemmalle"
#: ../data/50-mutter-navigation.xml.in.h:12
#, fuzzy
#| msgid "Move window one workspace to the right"
msgid "Move window one monitor to the right"
msgstr "Siirrä ikkunaa yksi työtila oikealle"
msgstr "Siirrä ikkuna yhden näytön verran oikealle"
#: ../data/50-mutter-navigation.xml.in.h:13
#, fuzzy
#| msgid "Move window one workspace up"
msgid "Move window one monitor up"
msgstr "Siirrä ikkunaa yksi työtila ylös"
msgstr "Siirrä ikkuna yhden näytön verran ylös"
#: ../data/50-mutter-navigation.xml.in.h:14
#, fuzzy
#| msgid "Move window one workspace down"
msgid "Move window one monitor down"
msgstr "Siirrä ikkunaa yksi työtila alas"
msgstr "Siirrä ikkuna yhden näytön verran alas"
#: ../data/50-mutter-navigation.xml.in.h:15
msgid "Switch applications"
msgstr "Vaihda sovelluksia"
#: ../data/50-mutter-navigation.xml.in.h:16
#| msgid "Switch applications"
msgid "Switch to previous application"
msgstr "Vaihda edelliseen sovellukseen"
#: ../data/50-mutter-navigation.xml.in.h:17
msgid "Switch windows"
msgstr "Vaihda ikkunoita"
#: ../data/50-mutter-navigation.xml.in.h:17
#: ../data/50-mutter-navigation.xml.in.h:18
#| msgid "Switch windows"
msgid "Switch to previous window"
msgstr "Vaihda edelliseen ikkunaan"
#: ../data/50-mutter-navigation.xml.in.h:19
msgid "Switch windows of an application"
msgstr "Vaihda sovelluksen ikkunoiden välillä"
#: ../data/50-mutter-navigation.xml.in.h:18
#: ../data/50-mutter-navigation.xml.in.h:20
#| msgid "Switch windows of an application"
msgid "Switch to previous window of an application"
msgstr "Vaihda sovelluksen edelliseen ikkunaan"
#: ../data/50-mutter-navigation.xml.in.h:21
#, fuzzy
msgid "Switch system controls"
msgstr "Vaihda järjestelmän kontrolleja"
#: ../data/50-mutter-navigation.xml.in.h:19
#: ../data/50-mutter-navigation.xml.in.h:22
#, fuzzy
msgid "Switch to previous system control"
msgstr "Vaihda järjestelmän kontrolleja"
#: ../data/50-mutter-navigation.xml.in.h:23
msgid "Switch windows directly"
msgstr "Vaihda ikkunoita suoraan"
#: ../data/50-mutter-navigation.xml.in.h:20
#: ../data/50-mutter-navigation.xml.in.h:24
msgid "Switch directly to previous window"
msgstr "Vaihda suoraan edelliseen ikkunaan"
#: ../data/50-mutter-navigation.xml.in.h:25
msgid "Switch windows of an app directly"
msgstr "Vaihda sovelluksen ikkunoiden välillä suoraan"
#: ../data/50-mutter-navigation.xml.in.h:21
#: ../data/50-mutter-navigation.xml.in.h:26
#, fuzzy
#| msgid "Switch windows of an application"
msgid "Switch directly to previous window of an app"
msgstr "Vaihda sovelluksen ikkunoiden välillä"
#: ../data/50-mutter-navigation.xml.in.h:27
#, fuzzy
msgid "Switch system controls directly"
msgstr "Vaihda järjestelmän kontrolleja suoraan"
#: ../data/50-mutter-navigation.xml.in.h:22
#: ../data/50-mutter-navigation.xml.in.h:28
#, fuzzy
msgid "Switch directly to previous system control"
msgstr "Vaihda järjestelmän kontrolleja"
#: ../data/50-mutter-navigation.xml.in.h:29
msgid "Hide all normal windows"
msgstr "Piilota kaikki tavalliset ikkunat"
#: ../data/50-mutter-navigation.xml.in.h:23
#: ../data/50-mutter-navigation.xml.in.h:30
msgid "Switch to workspace 1"
msgstr "Siirry työtilaan 1"
#: ../data/50-mutter-navigation.xml.in.h:24
#: ../data/50-mutter-navigation.xml.in.h:31
msgid "Switch to workspace 2"
msgstr "Siirry työtilaan 2"
#: ../data/50-mutter-navigation.xml.in.h:25
#: ../data/50-mutter-navigation.xml.in.h:32
msgid "Switch to workspace 3"
msgstr "Siirry työtilaan 3"
#: ../data/50-mutter-navigation.xml.in.h:26
#: ../data/50-mutter-navigation.xml.in.h:33
msgid "Switch to workspace 4"
msgstr "Siirry työtilaan 4"
#: ../data/50-mutter-navigation.xml.in.h:27
#, fuzzy
#: ../data/50-mutter-navigation.xml.in.h:34
#| msgid "Switch to workspace 1"
msgid "Switch to last workspace"
msgstr "Siirry työtilaan 1"
msgstr "Siirry viimeiseen työtilaan"
#: ../data/50-mutter-navigation.xml.in.h:28
#: ../data/50-mutter-navigation.xml.in.h:35
msgid "Move to workspace left"
msgstr "Siirrä vasemmalla olevaan työtilaan"
#: ../data/50-mutter-navigation.xml.in.h:29
#: ../data/50-mutter-navigation.xml.in.h:36
msgid "Move to workspace right"
msgstr "Siirrä oikealla olevaan työtilaan"
#: ../data/50-mutter-navigation.xml.in.h:30
#: ../data/50-mutter-navigation.xml.in.h:37
msgid "Move to workspace above"
msgstr "Siirrä yllä olevaan työtilaan"
#: ../data/50-mutter-navigation.xml.in.h:31
#: ../data/50-mutter-navigation.xml.in.h:38
msgid "Move to workspace below"
msgstr "Siirrä alla olevaan työtilaan"
@ -369,7 +398,7 @@ msgstr ""
#: ../data/org.gnome.mutter.gschema.xml.in.h:19
msgid "Place new windows in the center"
msgstr ""
msgstr "Aseta uudet ikkunat keskelle näyttöä"
#: ../data/org.gnome.mutter.gschema.xml.in.h:20
msgid ""
@ -387,62 +416,53 @@ msgid "Cancel tab popup"
msgstr ""
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:1
#, fuzzy
#| msgid "Switch to workspace 1"
msgid "Switch to VT 1"
msgstr "Siirry työtilaan 1"
msgstr "Siirry virtuaalikonsoliin 1"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:2
#, fuzzy
#| msgid "Switch to workspace 2"
msgid "Switch to VT 2"
msgstr "Siirry työtilaan 2"
msgstr "Siirry virtuaalikonsoliin 2"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:3
#, fuzzy
#| msgid "Switch to workspace 3"
msgid "Switch to VT 3"
msgstr "Siirry työtilaan 3"
msgstr "Siirry virtuaalikonsoliin 3"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:4
#, fuzzy
#| msgid "Switch to workspace 4"
msgid "Switch to VT 4"
msgstr "Siirry työtilaan 4"
msgstr "Siirry virtuaalikonsoliin 4"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:5
#, fuzzy
#| msgid "Switch to workspace 1"
msgid "Switch to VT 5"
msgstr "Siirry työtilaan 1"
msgstr "Siirry virtuaalikonsoliin 5"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:6
#, fuzzy
#| msgid "Switch to workspace 1"
msgid "Switch to VT 6"
msgstr "Siirry työtilaan 1"
msgstr "Siirry virtuaalikonsoliin 6"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:7
#, fuzzy
#| msgid "Switch to workspace 1"
msgid "Switch to VT 7"
msgstr "Siirry työtilaan 1"
msgstr "Siirry virtuaalikonsoliin 7"
#: ../src/backends/meta-monitor-manager.c:412
msgid "Built-in display"
msgstr "Sisäänrakennettu näyttö"
#: ../src/backends/meta-monitor-manager.c:437
#, fuzzy
#| msgid "Unknown %s"
msgid "Unknown"
msgstr "Tuntematon %s"
msgstr "Tuntematon"
#: ../src/backends/meta-monitor-manager.c:439
#, fuzzy
#| msgid "Unknown %s"
msgid "Unknown Display"
msgstr "Tuntematon %s"
msgstr "Tuntematon näyttö"
#. TRANSLATORS: this is a monitor vendor name, followed by a
#. * size in inches, like 'Dell 15"'
@ -450,23 +470,19 @@ msgstr "Tuntematon %s"
#: ../src/backends/meta-monitor-manager.c:447
#, c-format
msgid "%s %s"
msgstr ""
msgstr "%s %s"
#. 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:450
#: ../src/compositor/compositor.c:443
#, c-format
msgid ""
"Another compositing manager is already running on screen %i on display \""
"%s\"."
"Another compositing manager is already running on screen %i on display \"%s"
"\"."
msgstr ""
"Näytön ”%2$s” ruudullä %1$d on jo käynnissä toinen ikkunoidenladontaohjelman."
#: ../src/compositor/meta-background.c:1044
msgid "background texture could not be created from file"
msgstr ""
#: ../src/core/bell.c:214
#: ../src/core/bell.c:185
msgid "Bell event"
msgstr "Äänimerkki"
@ -494,49 +510,49 @@ msgstr "_Odota"
msgid "_Force Quit"
msgstr "Sulje _väkisin"
#: ../src/core/display.c:539
#: ../src/core/display.c:547
#, c-format
msgid "Failed to open X Window System display '%s'\n"
msgstr "X-ikkunointijärjestelmän näytön ”%s” avaaminen epäonnistui\n"
#: ../src/core/main.c:172
#: ../src/core/main.c:176
msgid "Disable connection to session manager"
msgstr "Estä yhteys sessionhallintaan"
#: ../src/core/main.c:178
#: ../src/core/main.c:182
msgid "Replace the running window manager"
msgstr "Vaihda käytössä oleva ikkunanhallinta"
#: ../src/core/main.c:184
#: ../src/core/main.c:188
msgid "Specify session management ID"
msgstr "Anna sessionhallinnan ID"
#: ../src/core/main.c:189
#: ../src/core/main.c:193
msgid "X Display to use"
msgstr "Käytettävä X-näyttö"
#: ../src/core/main.c:195
#: ../src/core/main.c:199
msgid "Initialize session from savefile"
msgstr "Alusta sessio tiedostosta"
#: ../src/core/main.c:201
#: ../src/core/main.c:205
msgid "Make X calls synchronous"
msgstr "Käytä synkronisia X-kutsuja"
#: ../src/core/main.c:207
#: ../src/core/main.c:212
msgid "Run as a wayland compositor"
msgstr ""
msgstr "Suorita wayland-koostajana"
#: ../src/core/main.c:214
#: ../src/core/main.c:220
msgid "Run as a full display server, rather than nested"
msgstr ""
#: ../src/core/main.c:450
#: ../src/core/main.c:459
#, c-format
msgid "Failed to scan themes directory: %s\n"
msgstr "Teemakansion lukeminen epäonnistui: %s\n"
#: ../src/core/main.c:466
#: ../src/core/main.c:475
#, c-format
msgid ""
"Could not find a theme! Be sure %s exists and contains the usual themes.\n"
@ -567,17 +583,17 @@ msgstr "Näytä versio"
msgid "Mutter plugin to use"
msgstr "Käytettävä Mutter-liitännäinen"
#: ../src/core/prefs.c:2102
#: ../src/core/prefs.c:2101
#, c-format
msgid "Workspace %d"
msgstr "Työtila %d"
#: ../src/core/screen.c:553
#: ../src/core/screen.c:548
#, c-format
msgid "Screen %d on display '%s' is invalid\n"
msgstr "Näytön ”%2$s” ruutu %1$d ei ole kelvollinen\n"
#: ../src/core/screen.c:569
#: ../src/core/screen.c:564
#, c-format
msgid ""
"Screen %d on display \"%s\" already has a window manager; try using the --"
@ -586,7 +602,7 @@ msgstr ""
"Näytön ”%2$s” ruudulla %1$d on jo ikkunointiohjelma: kokeile valitsinta --"
"replace, jos haluat korvata nykyisen ikkunointiohjelman.\n"
#: ../src/core/screen.c:662
#: ../src/core/screen.c:657
#, c-format
msgid "Screen %d on display \"%s\" already has a window manager\n"
msgstr "Näytön ”%2$s” ruudulla %1$d on jo ikkunointiohjelma\n"
@ -650,8 +666,8 @@ msgid ""
"GTK custom color specification must have color name and fallback in "
"parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\""
msgstr ""
"GTK-värimääritteessä täytyy olla värin nimi ja vara-arvo suluissa, esim. "
"gtk:custom(foo,bar). ”%s” ei jäsenny"
"GTK-värimääritteessä täytyy olla värin nimi ja vara-arvo suluissa, esim. gtk:"
"custom(foo,bar). ”%s” ei jäsenny"
#: ../src/ui/theme.c:1227
#, c-format
@ -683,8 +699,8 @@ msgstr ""
#: ../src/ui/theme.c:1300
#, c-format
msgid ""
"GTK color specification must have a close bracket after the state, e.g. "
"gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""
"GTK color specification must have a close bracket after the state, e.g. gtk:"
"fg[NORMAL] where NORMAL is the state; could not parse \"%s\""
msgstr ""
"GTK-värimääritteessä täytyy olla loppuhakasulku tilan jälkeen. Esimerkiksi "
"gtk:fg[NORMAL], jossa NORMAL on tila. ”%s” ei jäsenny"

1751
po/gu.po

File diff suppressed because it is too large Load Diff

1942
po/hi.po

File diff suppressed because it is too large Load Diff

1333
po/hu.po

File diff suppressed because it is too large Load Diff

926
po/id.po

File diff suppressed because it is too large Load Diff

1346
po/it.po

File diff suppressed because it is too large Load Diff

1966
po/kn.po

File diff suppressed because it is too large Load Diff

1022
po/ko.po

File diff suppressed because it is too large Load Diff

157
po/lt.po
View File

@ -13,8 +13,8 @@ msgstr ""
"Project-Id-Version: lt\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?"
"product=mutter&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2014-07-05 09:54+0000\n"
"PO-Revision-Date: 2014-07-05 13:56+0300\n"
"POT-Creation-Date: 2014-09-10 09:53+0000\n"
"PO-Revision-Date: 2014-09-10 20:22+0300\n"
"Last-Translator: Aurimas Černius <aurisc4@gmail.com>\n"
"Language-Team: Lietuvių <gnome-lt@lists.akl.lt>\n"
"Language: lt\n"
@ -46,7 +46,6 @@ msgid "Move window to workspace 4"
msgstr "Perkelti langą į darbalaukį Nr.4"
#: ../data/50-mutter-navigation.xml.in.h:6
#| msgid "Move window to workspace 1"
msgid "Move window to last workspace"
msgstr "Perkelti langą į pastarąjį darbalaukį"
@ -84,70 +83,103 @@ msgstr "Perkelti langą į žemiau esantį monitorių"
#: ../data/50-mutter-navigation.xml.in.h:15
msgid "Switch applications"
msgstr "Persijungti tarp programų"
msgstr "Pereiti tarp programų"
#: ../data/50-mutter-navigation.xml.in.h:16
msgid "Switch windows"
msgstr "Persijungti tarp langų"
#| msgid "Switch applications"
msgid "Switch to previous application"
msgstr "Pereiti į ankstesnę programą"
#: ../data/50-mutter-navigation.xml.in.h:17
msgid "Switch windows of an application"
msgstr "Persijungti tarp programos langų"
msgid "Switch windows"
msgstr "Pereiti tarp langų"
#: ../data/50-mutter-navigation.xml.in.h:18
msgid "Switch system controls"
msgstr "Persijungti tarp sistemos valdiklių"
#| msgid "Switch windows"
msgid "Switch to previous window"
msgstr "Pereiti į ankstesnį langą"
#: ../data/50-mutter-navigation.xml.in.h:19
msgid "Switch windows directly"
msgstr "Tiesiogiai persijungti tarp langų"
msgid "Switch windows of an application"
msgstr "Pereiti tarp programos langų"
#: ../data/50-mutter-navigation.xml.in.h:20
msgid "Switch windows of an app directly"
msgstr "Tiesiogiai persijungti tarp programos langų"
#| msgid "Switch windows of an application"
msgid "Switch to previous window of an application"
msgstr "Pereiti į ankstesnį programos langą"
#: ../data/50-mutter-navigation.xml.in.h:21
msgid "Switch system controls directly"
msgstr "Tiesiogiai persijungti tarp sistemos valdiklių"
msgid "Switch system controls"
msgstr "Pereiti tarp sistemos valdiklių"
#: ../data/50-mutter-navigation.xml.in.h:22
#| msgid "Switch system controls"
msgid "Switch to previous system control"
msgstr "Pereiti prie ankstesnio sistemos valdiklio"
#: ../data/50-mutter-navigation.xml.in.h:23
msgid "Switch windows directly"
msgstr "Tiesiogiai pereiti tarp langų"
#: ../data/50-mutter-navigation.xml.in.h:24
msgid "Switch directly to previous window"
msgstr "Tiesiogiai pereiti į ankstesnį langą"
#: ../data/50-mutter-navigation.xml.in.h:25
msgid "Switch windows of an app directly"
msgstr "Tiesiogiai pereiti tarp programos langų"
#: ../data/50-mutter-navigation.xml.in.h:26
#| msgid "Switch windows of an application"
msgid "Switch directly to previous window of an app"
msgstr "Tiesiogiai pereiti prie ankstesnio programos lango"
#: ../data/50-mutter-navigation.xml.in.h:27
msgid "Switch system controls directly"
msgstr "Tiesiogiai pereiti tarp sistemos valdiklių"
#: ../data/50-mutter-navigation.xml.in.h:28
#| msgid "Switch system controls"
msgid "Switch directly to previous system control"
msgstr "Tiesiogiai pereiti prie ankstesnio sistemos valdiklio"
#: ../data/50-mutter-navigation.xml.in.h:29
msgid "Hide all normal windows"
msgstr "Paslėpti visus įprastinius langus"
#: ../data/50-mutter-navigation.xml.in.h:23
#: ../data/50-mutter-navigation.xml.in.h:30
msgid "Switch to workspace 1"
msgstr "Persijungti į darbalaukį Nr.1"
#: ../data/50-mutter-navigation.xml.in.h:24
#: ../data/50-mutter-navigation.xml.in.h:31
msgid "Switch to workspace 2"
msgstr "Persijungti į darbalaukį Nr.2"
#: ../data/50-mutter-navigation.xml.in.h:25
#: ../data/50-mutter-navigation.xml.in.h:32
msgid "Switch to workspace 3"
msgstr "Persijungti į darbalaukį Nr.3"
#: ../data/50-mutter-navigation.xml.in.h:26
#: ../data/50-mutter-navigation.xml.in.h:33
msgid "Switch to workspace 4"
msgstr "Persijungti į darbalaukį Nr.4"
#: ../data/50-mutter-navigation.xml.in.h:27
#| msgid "Switch to workspace 1"
#: ../data/50-mutter-navigation.xml.in.h:34
msgid "Switch to last workspace"
msgstr "Persijungti į pastarąjį darbalaukį"
#: ../data/50-mutter-navigation.xml.in.h:28
#: ../data/50-mutter-navigation.xml.in.h:35
msgid "Move to workspace left"
msgstr "Perkelti į darbalaukį kairėje"
#: ../data/50-mutter-navigation.xml.in.h:29
#: ../data/50-mutter-navigation.xml.in.h:36
msgid "Move to workspace right"
msgstr "Perkelti į darbalaukį dešinėje"
#: ../data/50-mutter-navigation.xml.in.h:30
#: ../data/50-mutter-navigation.xml.in.h:37
msgid "Move to workspace above"
msgstr "Perkelti į darbalaukį viršuje"
#: ../data/50-mutter-navigation.xml.in.h:31
#: ../data/50-mutter-navigation.xml.in.h:38
msgid "Move to workspace below"
msgstr "Perkelti į darbalaukį apačioje"
@ -384,37 +416,30 @@ msgid "Cancel tab popup"
msgstr "Atšaukti tab iššokimą"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:1
#| msgid "Switch to workspace 1"
msgid "Switch to VT 1"
msgstr "Persijungti į VT 1"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:2
#| msgid "Switch to workspace 2"
msgid "Switch to VT 2"
msgstr "Persijungti į VT 2"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:3
#| msgid "Switch to workspace 3"
msgid "Switch to VT 3"
msgstr "Persijungti į VT 3"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:4
#| msgid "Switch to workspace 4"
msgid "Switch to VT 4"
msgstr "Persijungti į VT 4"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:5
#| msgid "Switch to workspace 1"
msgid "Switch to VT 5"
msgstr "Persijungti į VT 5"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:6
#| msgid "Switch to workspace 1"
msgid "Switch to VT 6"
msgstr "Persijungti į VT 6"
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:7
#| msgid "Switch to workspace 1"
msgid "Switch to VT 7"
msgstr "Persijungti į VT 7"
@ -440,87 +465,83 @@ msgstr "%s %s"
#. 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:464
#: ../src/compositor/compositor.c:443
#, c-format
msgid ""
"Another compositing manager is already running on screen %i on display \"%s"
"\"."
msgstr "Kita kompozicijos valdyklė jau veikia ekrane %i vaizduoklyje „%s“."
#: ../src/compositor/meta-background.c:990
msgid "background texture could not be created from file"
msgstr "nepavyko sukurti fono tekstūros iš failo"
#: ../src/core/bell.c:215
#: ../src/core/bell.c:185
msgid "Bell event"
msgstr "Skambučio įvykis"
#: ../src/core/delete.c:129
#: ../src/core/delete.c:127
#, c-format
msgid "“%s” is not responding."
msgstr "%s neatsiliepia į komandas."
#: ../src/core/delete.c:131
#: ../src/core/delete.c:129
msgid "Application is not responding."
msgstr "Programa neatsiliepia į komandas."
#: ../src/core/delete.c:136
#: ../src/core/delete.c:134
msgid ""
"You may choose to wait a short while for it to continue or force the "
"application to quit entirely."
msgstr "Galite šiek tiek palaukti arba priverstinai uždaryti programą."
#: ../src/core/delete.c:143
#: ../src/core/delete.c:141
msgid "_Wait"
msgstr "_Laukti"
#: ../src/core/delete.c:143
#: ../src/core/delete.c:141
msgid "_Force Quit"
msgstr "_Priverstinai išeiti"
#: ../src/core/display.c:448
#: ../src/core/display.c:547
#, c-format
msgid "Failed to open X Window System display '%s'\n"
msgstr "Nepavyko atverti X Window sistemos ekrano „%s“\n"
#: ../src/core/main.c:172
#: ../src/core/main.c:176
msgid "Disable connection to session manager"
msgstr "Išjungti susijungimą su sesijos valdykle"
#: ../src/core/main.c:178
#: ../src/core/main.c:182
msgid "Replace the running window manager"
msgstr "Pakeisti veikiančią langų valdyklę"
#: ../src/core/main.c:184
#: ../src/core/main.c:188
msgid "Specify session management ID"
msgstr "Nurodyti sesijos valdymo ID"
#: ../src/core/main.c:189
#: ../src/core/main.c:193
msgid "X Display to use"
msgstr "Naudotinas X ekranas"
#: ../src/core/main.c:195
#: ../src/core/main.c:199
msgid "Initialize session from savefile"
msgstr "Inicializuoti sesiją iš išsaugojimo failo"
#: ../src/core/main.c:201
#: ../src/core/main.c:205
msgid "Make X calls synchronous"
msgstr "Sinchronizuoti X iškvietimus"
#: ../src/core/main.c:207
#: ../src/core/main.c:212
msgid "Run as a wayland compositor"
msgstr "Vykdyti kaip wayland kompozitorių"
#: ../src/core/main.c:214
#: ../src/core/main.c:220
msgid "Run as a full display server, rather than nested"
msgstr "Vykdyti kaip visą vaizduoklio serverį, o ne vidinį"
#: ../src/core/main.c:448
#: ../src/core/main.c:451
#, c-format
msgid "Failed to scan themes directory: %s\n"
msgstr "Nepavyko nuskanuoti temų aplanko: %s\n"
#: ../src/core/main.c:464
#: ../src/core/main.c:467
#, c-format
msgid ""
"Could not find a theme! Be sure %s exists and contains the usual themes.\n"
@ -553,17 +574,17 @@ msgstr "Parodyti versiją"
msgid "Mutter plugin to use"
msgstr "Naudojamas Mutter įskiepis"
#: ../src/core/prefs.c:2086
#: ../src/core/prefs.c:2101
#, c-format
msgid "Workspace %d"
msgstr "Darbalaukis %d"
#: ../src/core/screen.c:539
#: ../src/core/screen.c:548
#, c-format
msgid "Screen %d on display '%s' is invalid\n"
msgstr "Ekranas %d vaizduoklyje „%s“ netinkamas\n"
#: ../src/core/screen.c:555
#: ../src/core/screen.c:564
#, c-format
msgid ""
"Screen %d on display \"%s\" already has a window manager; try using the --"
@ -572,7 +593,7 @@ msgstr ""
"Ekranas %d vaizduoklyje „%s“ jau turi langų valdyklę; pabandykite "
"pasinaudoti parinktimi --replace, jei norite pakeisti esamą langų valdyklę.\n"
#: ../src/core/screen.c:660
#: ../src/core/screen.c:657
#, c-format
msgid "Screen %d on display \"%s\" already has a window manager\n"
msgstr "Ekranas %d vaizduoklyje „%s“ jau turi langų valdyklę\n"
@ -840,7 +861,7 @@ msgstr "Koordinačių išraiška neturi jokių operatorių ar operandų"
msgid "Theme contained an expression that resulted in an error: %s\n"
msgstr "Temoje esanti išraiška sukėlė klaidą: %s\n"
#: ../src/ui/theme.c:4467
#: ../src/ui/theme.c:4455
#, c-format
msgid ""
"<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be "
@ -849,25 +870,25 @@ msgstr ""
"Šiam rėmelio stiliui turi būti nurodytas <button function=\"%s\" state=\"%s"
"\" draw_ops=\"kažkokswhatever\"/> požymis"
#: ../src/ui/theme.c:4982 ../src/ui/theme.c:5007
#: ../src/ui/theme.c:4970 ../src/ui/theme.c:4995
#, c-format
msgid ""
"Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
msgstr ""
"Trūksta <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"kažkoks\"/>"
#: ../src/ui/theme.c:5053
#: ../src/ui/theme.c:5041
#, c-format
msgid "Failed to load theme \"%s\": %s\n"
msgstr "Nepavyko paleisti temos \"%s\": %s\n"
#: ../src/ui/theme.c:5189 ../src/ui/theme.c:5196 ../src/ui/theme.c:5203
#: ../src/ui/theme.c:5210 ../src/ui/theme.c:5217
#: ../src/ui/theme.c:5177 ../src/ui/theme.c:5184 ../src/ui/theme.c:5191
#: ../src/ui/theme.c:5198 ../src/ui/theme.c:5205
#, c-format
msgid "No <%s> set for theme \"%s\""
msgstr "Temoje \"%2$s\" trūksta <%1$s> nustatymų"
#: ../src/ui/theme.c:5225
#: ../src/ui/theme.c:5213
#, c-format
msgid ""
"No frame style set for window type \"%s\" in theme \"%s\", add a <window "
@ -876,7 +897,7 @@ msgstr ""
"Rėmelio stilius nenurodytas lango tipui \"%s\" temoje \"%s\", pridėkite "
"<window type=\"%s\" style_set=\"kažkoks\"/> elementą"
#: ../src/ui/theme.c:5632 ../src/ui/theme.c:5694 ../src/ui/theme.c:5757
#: ../src/ui/theme.c:5620 ../src/ui/theme.c:5682 ../src/ui/theme.c:5745
#, c-format
msgid ""
"User-defined constants must begin with a capital letter; \"%s\" does not"
@ -884,7 +905,7 @@ msgstr ""
"Naudotojo nustatytos konstantos turi prasidėti didžiąja raide; „%s“ nėra "
"didžioji"
#: ../src/ui/theme.c:5640 ../src/ui/theme.c:5702 ../src/ui/theme.c:5765
#: ../src/ui/theme.c:5628 ../src/ui/theme.c:5690 ../src/ui/theme.c:5753
#, c-format
msgid "Constant \"%s\" has already been defined"
msgstr "Konstanta „%s“ jau aprašyta"
@ -1281,7 +1302,7 @@ msgstr ""
"Šie langai nepalaiko &quot;išsaugoti esamus nustatymus&quot; komandos ir "
"turi būti paleisti rankiniu būdu, kai prisijungsite kitą kartą."
#: ../src/x11/window-props.c:465
#: ../src/x11/window-props.c:515
#, c-format
msgid "%s (on %s)"
msgstr "%s (kompiuteryje %s)"

1301
po/lv.po

File diff suppressed because it is too large Load Diff

1802
po/mr.po

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: mutter 3.13.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-08-23 13:36+0200\n"
"POT-Creation-Date: 2014-09-06 14:13+0200\n"
"PO-Revision-Date: 2014-08-23 13:37+0200\n"
"Last-Translator: Kjartan Maraas <kmaraas@gnome.org>\n"
"Language-Team: Norwegian bokmål <i18n-no@lister.ping.uio.no>\n"
@ -445,17 +445,13 @@ msgstr "%s %s"
#. 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:441
#: ../src/compositor/compositor.c:443
#, c-format
msgid ""
"Another compositing manager is already running on screen %i on display \"%s"
"\"."
msgstr "En annen compositing manager kjører skjerm %i på display «%s»."
#: ../src/compositor/meta-background.c:1044
msgid "background texture could not be created from file"
msgstr "bakgrunnstekstur kunne ikke lages fra fil"
#: ../src/core/bell.c:185
msgid "Bell event"
msgstr "Klokkehendelse"
@ -1269,3 +1265,6 @@ msgstr ""
#, c-format
msgid "%s (on %s)"
msgstr "%s (på %s)"
#~ msgid "background texture could not be created from file"
#~ msgstr "bakgrunnstekstur kunne ikke lages fra fil"

1800
po/or.po

File diff suppressed because it is too large Load Diff

1299
po/pa.po

File diff suppressed because it is too large Load Diff

1052
po/pl.po

File diff suppressed because it is too large Load Diff

612
po/ru.po

File diff suppressed because it is too large Load Diff

1691
po/sk.po

File diff suppressed because it is too large Load Diff

1300
po/sr.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2152
po/sv.po

File diff suppressed because it is too large Load Diff

1836
po/ta.po

File diff suppressed because it is too large Load Diff

1865
po/te.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

51
src/Makefile-tests.am Normal file
View File

@ -0,0 +1,51 @@
# A framework for running scripted tests
if HAVE_WAYLAND
if BUILDOPT_INSTALL_TESTS
stackingdir = $(pkgdatadir)/tests/stacking
dist_stacking_DATA = \
tests/stacking/basic-x11.metatest \
tests/stacking/basic-wayland.metatest \
tests/stacking/minimized.metatest \
tests/stacking/mixed-windows.metatest \
tests/stacking/override-redirect.metatest
mutter-all.test: tests/mutter-all.test.in
$(AM_V_GEN) sed -e "s|@libexecdir[@]|$(libexecdir)|g" $< > $@.tmp && mv $@.tmp $@
installedtestsdir = $(datadir)/installed-tests/mutter
installedtests_DATA = mutter-all.test
installedtestsbindir = $(libexecdir)/installed-tests/mutter
installedtestsbin_PROGRAMS = mutter-test-client mutter-test-runner
else
noinst_PROGRAMS += mutter-test-client mutter-test-runner
endif
EXTRA_DIST += tests/mutter-all.test.in
mutter_test_client_SOURCES = tests/test-client.c
mutter_test_client_LDADD = $(MUTTER_LIBS) libmutter.la
mutter_test_runner_SOURCES = tests/test-runner.c
mutter_test_runner_LDADD = $(MUTTER_LIBS) libmutter.la
.PHONY: run-tests
run-tests: mutter-test-client mutter-test-runner
./mutter-test-runner $(dist_stacking_DATA)
endif
# Some random test programs for bits of the code
testboxes_SOURCES = core/testboxes.c
testgradient_SOURCES = ui/testgradient.c
testasyncgetprop_SOURCES = x11/testasyncgetprop.c
noinst_PROGRAMS+=testboxes testgradient testasyncgetprop
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la

View File

@ -5,6 +5,8 @@ lib_LTLIBRARIES = libmutter.la
SUBDIRS=compositor/plugins
EXTRA_DIST =
AM_CPPFLAGS = \
-DCLUTTER_ENABLE_COMPOSITOR_API \
-DCLUTTER_ENABLE_EXPERIMENTAL_API \
@ -100,11 +102,17 @@ libmutter_la_SOURCES = \
compositor/compositor.c \
compositor/compositor-private.h \
compositor/meta-background.c \
compositor/meta-background-private.h \
compositor/meta-background-actor.c \
compositor/meta-background-actor-private.h \
compositor/meta-background-image.c \
compositor/meta-background-group.c \
compositor/meta-cullable.c \
compositor/meta-cullable.h \
compositor/meta-dnd-actor.c \
compositor/meta-dnd-actor-private.h \
compositor/meta-feedback-actor.c \
compositor/meta-feedback-actor-private.h \
compositor/meta-module.c \
compositor/meta-module.h \
compositor/meta-plugin.c \
@ -133,6 +141,7 @@ libmutter_la_SOURCES = \
meta/compositor.h \
meta/meta-background.h \
meta/meta-background-actor.h \
meta/meta-background-image.h \
meta/meta-background-group.h \
meta/meta-plugin.h \
meta/meta-shadow-factory.h \
@ -225,6 +234,10 @@ libmutter_la_SOURCES += \
wayland/meta-xwayland.c \
wayland/meta-xwayland.h \
wayland/meta-xwayland-private.h \
wayland/meta-wayland-buffer.c \
wayland/meta-wayland-buffer.h \
wayland/meta-wayland-region.c \
wayland/meta-wayland-region.h \
wayland/meta-wayland-data-device.c \
wayland/meta-wayland-data-device.h \
wayland/meta-wayland-keyboard.c \
@ -282,9 +295,10 @@ libmutterinclude_headers = \
meta/keybindings.h \
meta/main.h \
meta/meta-backend.h \
meta/meta-background-actor.h \
meta/meta-background-group.h \
meta/meta-background.h \
meta/meta-background-actor.h \
meta/meta-background-image.h \
meta/meta-background-group.h \
meta/meta-cursor-tracker.h \
meta/meta-idle-monitor.h \
meta/meta-plugin.h \
@ -321,6 +335,7 @@ nodist_libmutterinclude_HEADERS = \
$(libmutterinclude_built_headers)
bin_PROGRAMS=mutter
noinst_PROGRAMS=
mutter_SOURCES = core/mutter.c
mutter_LDADD = $(MUTTER_LIBS) libmutter.la
@ -329,6 +344,8 @@ libexec_PROGRAMS = mutter-restart-helper
mutter_restart_helper_SOURCES = core/restart-helper.c
mutter_restart_helper_LDADD = $(MUTTER_LIBS)
include Makefile-tests.am
if HAVE_INTROSPECTION
include $(INTROSPECTION_MAKEFILE)
@ -362,16 +379,6 @@ Meta-$(api_version).gir: libmutter.la
endif
testboxes_SOURCES = core/testboxes.c
testgradient_SOURCES = ui/testgradient.c
testasyncgetprop_SOURCES = x11/testasyncgetprop.c
noinst_PROGRAMS=testboxes testgradient testasyncgetprop
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
CLEANFILES = \
@ -385,7 +392,7 @@ DISTCLEANFILES = \
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libmutter.pc
EXTRA_DIST = \
EXTRA_DIST += \
$(wayland_protocols) \
libmutter.pc.in \
mutter-enum-types.h.in \

View File

@ -189,7 +189,5 @@ struct MonitorInfo
};
MonitorInfo *decode_edid (const uchar *data);
char *make_display_name (const MonitorInfo *info);
char *make_display_size_string (int width_mm, int height_mm);
#endif

View File

@ -97,6 +97,62 @@ on_monitors_changed (MetaMonitorManager *monitors,
meta_backend_sync_screen_size (backend);
}
static MetaIdleMonitor *
meta_backend_create_idle_monitor (MetaBackend *backend,
int device_id)
{
return META_BACKEND_GET_CLASS (backend)->create_idle_monitor (backend, device_id);
}
static void
create_device_monitor (MetaBackend *backend,
int device_id)
{
g_assert (backend->device_monitors[device_id] == NULL);
backend->device_monitors[device_id] = meta_backend_create_idle_monitor (backend, device_id);
backend->device_id_max = MAX (backend->device_id_max, device_id);
}
static void
destroy_device_monitor (MetaBackend *backend,
int device_id)
{
g_clear_object (&backend->device_monitors[device_id]);
if (device_id == backend->device_id_max)
{
/* Reset the max device ID */
int i, new_max = 0;
for (i = 0; i < backend->device_id_max; i++)
if (backend->device_monitors[i] != NULL)
new_max = i;
backend->device_id_max = new_max;
}
}
static void
on_device_added (ClutterDeviceManager *device_manager,
ClutterInputDevice *device,
gpointer user_data)
{
MetaBackend *backend = META_BACKEND (user_data);
int device_id = clutter_input_device_get_device_id (device);
create_device_monitor (backend, device_id);
}
static void
on_device_removed (ClutterDeviceManager *device_manager,
ClutterInputDevice *device,
gpointer user_data)
{
MetaBackend *backend = META_BACKEND (user_data);
int device_id = clutter_input_device_get_device_id (device);
destroy_device_monitor (backend, device_id);
}
static void
meta_backend_real_post_init (MetaBackend *backend)
{
@ -113,6 +169,30 @@ meta_backend_real_post_init (MetaBackend *backend)
meta_backend_sync_screen_size (backend);
priv->cursor_renderer = META_BACKEND_GET_CLASS (backend)->create_cursor_renderer (backend);
{
ClutterDeviceManager *manager;
GSList *devices, *l;
/* Create the core device monitor. */
create_device_monitor (backend, 0);
manager = clutter_device_manager_get_default ();
g_signal_connect_object (manager, "device-added",
G_CALLBACK (on_device_added), backend, 0);
g_signal_connect_object (manager, "device-removed",
G_CALLBACK (on_device_removed), backend, 0);
devices = clutter_device_manager_list_devices (manager);
for (l = devices; l != NULL; l = l->next)
{
ClutterInputDevice *device = l->data;
on_device_added (manager, device, backend);
}
g_slist_free (devices);
}
}
static MetaCursorRenderer *
@ -174,6 +254,12 @@ meta_backend_class_init (MetaBackendClass *klass)
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
g_signal_new ("keymap-layout-group-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_UINT);
}
static void
@ -182,23 +268,6 @@ meta_backend_init (MetaBackend *backend)
_backend = backend;
}
/* FIXME -- destroy device monitors at some point */
G_GNUC_UNUSED static void
destroy_device_monitor (MetaBackend *backend,
int device_id)
{
g_clear_object (&backend->device_monitors[device_id]);
if (device_id == backend->device_id_max)
backend->device_id_max--;
}
static MetaIdleMonitor *
meta_backend_create_idle_monitor (MetaBackend *backend,
int device_id)
{
return META_BACKEND_GET_CLASS (backend)->create_idle_monitor (backend, device_id);
}
static void
meta_backend_post_init (MetaBackend *backend)
{
@ -214,12 +283,6 @@ meta_backend_get_idle_monitor (MetaBackend *backend,
{
g_return_val_if_fail (device_id >= 0 && device_id < 256, NULL);
if (!backend->device_monitors[device_id])
{
backend->device_monitors[device_id] = meta_backend_create_idle_monitor (backend, device_id);
backend->device_id_max = MAX (backend->device_id_max, device_id);
}
return backend->device_monitors[device_id];
}
@ -397,6 +460,7 @@ static GSourceFuncs event_funcs = {
void
meta_clutter_init (void)
{
ClutterSettings *clutter_settings;
GSource *source;
meta_create_backend ();
@ -404,6 +468,13 @@ meta_clutter_init (void)
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
g_error ("Unable to initialize Clutter.\n");
/*
* XXX: We cannot handle high dpi scaling yet, so fix the scale to 1
* for now.
*/
clutter_settings = clutter_settings_get_default ();
g_object_set (clutter_settings, "window-scaling-factor", 1, NULL);
source = g_source_new (&event_funcs, sizeof (GSource));
g_source_attach (source, NULL);
g_source_unref (source);

View File

@ -29,8 +29,11 @@
typedef struct {
CoglTexture2D *texture;
struct gbm_bo *bo;
int hot_x, hot_y;
#ifdef HAVE_NATIVE_BACKEND
struct gbm_bo *bo;
#endif
} MetaCursorImage;
struct _MetaCursorReference {
@ -44,8 +47,10 @@ CoglTexture *meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor
int *hot_x,
int *hot_y);
#ifdef HAVE_NATIVE_BACKEND
struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
int *hot_x,
int *hot_y);
#endif
#endif /* META_CURSOR_PRIVATE_H */

View File

@ -56,8 +56,11 @@ static void
meta_cursor_image_free (MetaCursorImage *image)
{
cogl_object_unref (image->texture);
#ifdef HAVE_NATIVE_BACKEND
if (image->bo)
gbm_bo_destroy (image->bo);
#endif
}
static void
@ -139,70 +142,90 @@ load_cursor_on_client (MetaCursor cursor)
meta_prefs_get_cursor_size ());
}
#ifdef HAVE_NATIVE_BACKEND
static void
get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
{
MetaBackend *meta_backend = meta_get_backend ();
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
{
meta_cursor_renderer_native_get_cursor_size (META_CURSOR_RENDERER_NATIVE (renderer), cursor_width, cursor_height);
return;
}
g_assert_not_reached ();
}
#endif
#ifdef HAVE_NATIVE_BACKEND
static void
meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
MetaCursorImage *image,
uint8_t *pixels,
int width,
int height,
uint width,
uint height,
int rowstride,
uint32_t gbm_format)
{
if (width > 64 || height > 64)
uint64_t cursor_width, cursor_height;
get_hardware_cursor_size (&cursor_width, &cursor_height);
if (width > cursor_width || height > cursor_height)
{
meta_warning ("Invalid theme cursor size (must be at most 64x64)\n");
meta_warning ("Invalid theme cursor size (must be at most %ux%u)\n",
(unsigned int)cursor_width, (unsigned int)cursor_height);
return;
}
if (gbm_device_is_format_supported (gbm, gbm_format,
GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))
{
uint8_t buf[4 * 64 * 64];
int i;
uint8_t buf[4 * cursor_width * cursor_height];
uint i;
image->bo = gbm_bo_create (gbm, 64, 64,
gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
image->bo = gbm_bo_create (gbm, cursor_width, cursor_height,
gbm_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
memset (buf, 0, sizeof(buf));
for (i = 0; i < height; i++)
memcpy (buf + i * 4 * 64, pixels + i * rowstride, width * 4);
memcpy (buf + i * 4 * cursor_width, pixels + i * rowstride, width * 4);
gbm_bo_write (image->bo, buf, 64 * 64 * 4);
gbm_bo_write (image->bo, buf, cursor_width * cursor_height * 4);
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
#endif
#ifdef HAVE_NATIVE_BACKEND
static struct gbm_device *
get_gbm_device (void)
{
#ifdef HAVE_NATIVE_BACKEND
MetaBackend *meta_backend = meta_get_backend ();
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
return meta_cursor_renderer_native_get_gbm_device (META_CURSOR_RENDERER_NATIVE (renderer));
#endif
return NULL;
else
return NULL;
}
#endif
static void
meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
XcursorImage *xc_image)
{
int width, height, rowstride;
uint width, height, rowstride;
CoglPixelFormat cogl_format;
uint32_t gbm_format;
ClutterBackend *clutter_backend;
CoglContext *cogl_context;
struct gbm_device *gbm;
width = xc_image->width;
height = xc_image->height;
rowstride = width * 4;
gbm_format = GBM_FORMAT_ARGB8888;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
#else
@ -221,13 +244,15 @@ meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
(uint8_t *) xc_image->pixels,
NULL);
gbm = get_gbm_device ();
#ifdef HAVE_NATIVE_BACKEND
struct gbm_device *gbm = get_gbm_device ();
if (gbm)
meta_cursor_image_load_gbm_buffer (gbm,
image,
(uint8_t *) xc_image->pixels,
width, height, rowstride,
gbm_format);
GBM_FORMAT_ARGB8888);
#endif
}
MetaCursorReference *
@ -256,13 +281,8 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
int hot_x,
int hot_y)
{
struct gbm_device *gbm = get_gbm_device ();
ClutterBackend *backend;
CoglContext *cogl_context;
struct wl_shm_buffer *shm_buffer;
uint32_t gbm_format;
int width, height;
image->hot_x = hot_x;
image->hot_y = hot_y;
@ -272,13 +292,19 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
image->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
#ifdef HAVE_NATIVE_BACKEND
struct gbm_device *gbm = get_gbm_device ();
if (gbm)
{
if (gbm)
uint32_t gbm_format;
uint64_t cursor_width, cursor_height;
uint width, height;
width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
{
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
@ -310,29 +336,28 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
width, height, rowstride,
gbm_format);
}
}
else
{
/* HW cursors must be 64x64, but 64x64 is huge, and no cursor theme actually uses
that, so themed cursors must be padded with transparent pixels to fill the
overlay. This is trivial if we have CPU access to the data, but it's not
possible if the buffer is in GPU memory (and possibly tiled too), so if we
don't get the right size, we fallback to GL.
*/
if (width != 64 || height != 64)
else
{
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
return;
}
/* HW cursors have a predefined size (at least 64x64), which usually is bigger than cursor theme
size, 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.
*/
get_hardware_cursor_size (&cursor_width, &cursor_height);
if (gbm)
{
image->bo = gbm_bo_import (gbm, GBM_BO_IMPORT_WL_BUFFER,
buffer, GBM_BO_USE_CURSOR_64X64);
if (width != cursor_width || height != cursor_height)
{
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
return;
}
image->bo = gbm_bo_import (gbm, GBM_BO_IMPORT_WL_BUFFER, buffer, GBM_BO_USE_CURSOR);
if (!image->bo)
meta_warning ("Importing HW cursor from wl_buffer failed\n");
}
}
#endif
}
MetaCursorReference *
@ -362,6 +387,7 @@ meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor,
return COGL_TEXTURE (cursor->image.texture);
}
#ifdef HAVE_NATIVE_BACKEND
struct gbm_bo *
meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
int *hot_x,
@ -373,6 +399,7 @@ meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
*hot_y = cursor->image.hot_y;
return cursor->image.bo;
}
#endif
MetaCursor
meta_cursor_reference_get_meta_cursor (MetaCursorReference *cursor)

View File

@ -796,27 +796,6 @@ make_config_key (MetaConfiguration *key,
key->n_outputs = o;
}
gboolean
meta_monitor_config_match_current (MetaMonitorConfig *self,
MetaMonitorManager *manager)
{
MetaOutput *outputs;
unsigned n_outputs;
MetaConfiguration key;
gboolean ok;
if (self->current == NULL)
return FALSE;
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
make_config_key (&key, outputs, n_outputs, -1);
ok = config_equal (&key, self->current);
config_clear (&key);
return ok;
}
gboolean
meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
{
@ -945,6 +924,19 @@ laptop_display_is_on (MetaConfiguration *config)
return FALSE;
}
static gboolean
multiple_outputs_are_enabled (MetaConfiguration *config)
{
unsigned int i, enabled;
enabled = 0;
for (i = 0; i < config->n_outputs; i++)
if (config->outputs[i].enabled)
enabled++;
return enabled > 1;
}
static MetaConfiguration *
make_laptop_lid_config (MetaConfiguration *reference)
{
@ -954,7 +946,7 @@ make_laptop_lid_config (MetaConfiguration *reference)
int x_after, y_after;
int x_offset, y_offset;
g_assert (reference->n_outputs > 1);
g_assert (multiple_outputs_are_enabled (reference));
new = g_slice_new0 (MetaConfiguration);
new->n_outputs = reference->n_outputs;
@ -1025,7 +1017,7 @@ meta_monitor_config_apply_stored (MetaMonitorConfig *self,
if (stored)
{
if (self->lid_is_closed &&
stored->n_outputs > 1 &&
multiple_outputs_are_enabled (stored) &&
laptop_display_is_on (stored))
{
if (apply_configuration (self, make_laptop_lid_config (stored),
@ -1287,7 +1279,7 @@ meta_monitor_config_make_default (MetaMonitorConfig *self,
if (default_config != NULL)
{
if (self->lid_is_closed &&
default_config->n_outputs > 1 &&
multiple_outputs_are_enabled (default_config) &&
laptop_display_is_on (default_config))
{
ok = apply_configuration (self, make_laptop_lid_config (default_config),
@ -1378,7 +1370,7 @@ turn_off_laptop_display (MetaMonitorConfig *self,
{
MetaConfiguration *new;
if (self->current->n_outputs == 1)
if (!multiple_outputs_are_enabled (self->current))
return;
new = make_laptop_lid_config (self->current);
@ -1789,7 +1781,6 @@ real_assign_crtcs (CrtcAssignment *assignment,
output_config->transform,
pass);
if (crtc_assignment_assign (assignment, crtc, &modes[j],
output_config->rect.x, output_config->rect.y,
output_config->transform,

View File

@ -36,9 +36,6 @@ GType meta_monitor_config_get_type (void) G_GNUC_CONST;
MetaMonitorConfig *meta_monitor_config_new (void);
gboolean meta_monitor_config_match_current (MetaMonitorConfig *config,
MetaMonitorManager *manager);
gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config,
MetaMonitorManager *manager);

View File

@ -44,12 +44,6 @@ enum {
SIGNALS_LAST
};
enum {
PROP_0,
PROP_POWER_SAVE_MODE,
PROP_LAST
};
static int signals[SIGNALS_LAST];
static void meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface *iface);
@ -167,11 +161,39 @@ make_logical_config (MetaMonitorManager *manager)
manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE);
}
static void
power_save_mode_changed (MetaMonitorManager *manager,
GParamSpec *pspec,
gpointer user_data)
{
MetaMonitorManagerClass *klass;
int mode = meta_dbus_display_config_get_power_save_mode (META_DBUS_DISPLAY_CONFIG (manager));
if (mode == META_POWER_SAVE_UNSUPPORTED)
return;
/* If DPMS is unsupported, force the property back. */
if (manager->power_save_mode == META_POWER_SAVE_UNSUPPORTED)
{
meta_dbus_display_config_set_power_save_mode (META_DBUS_DISPLAY_CONFIG (manager), META_POWER_SAVE_UNSUPPORTED);
return;
}
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
if (klass->set_power_save_mode)
klass->set_power_save_mode (manager, mode);
manager->power_save_mode = mode;
}
static void
meta_monitor_manager_constructed (GObject *object)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
g_signal_connect_object (manager, "notify::power-save-mode",
G_CALLBACK (power_save_mode_changed), manager, 0);
manager->in_init = TRUE;
manager->config = meta_monitor_config_new ();
@ -214,23 +236,6 @@ meta_monitor_manager_constructed (GObject *object)
manager->in_init = FALSE;
}
static void
meta_monitor_manager_set_power_save_mode (MetaMonitorManager *manager,
MetaPowerSave mode)
{
MetaMonitorManagerClass *klass;
if (manager->power_save_mode == META_POWER_SAVE_UNSUPPORTED ||
mode == META_POWER_SAVE_UNSUPPORTED)
return;
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
if (klass->set_power_save_mode)
klass->set_power_save_mode (manager, mode);
manager->power_save_mode = mode;
}
void
meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
int n_old_outputs)
@ -298,44 +303,6 @@ meta_monitor_manager_dispose (GObject *object)
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->dispose (object);
}
static void
meta_monitor_manager_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaMonitorManager *self = META_MONITOR_MANAGER (object);
switch (prop_id)
{
case PROP_POWER_SAVE_MODE:
meta_monitor_manager_set_power_save_mode (self, g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_monitor_manager_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaMonitorManager *self = META_MONITOR_MANAGER (object);
switch (prop_id)
{
case PROP_POWER_SAVE_MODE:
g_value_set_int (value, self->power_save_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GBytes *
meta_monitor_manager_real_read_edid (MetaMonitorManager *manager,
MetaOutput *output)
@ -356,8 +323,6 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = meta_monitor_manager_constructed;
object_class->get_property = meta_monitor_manager_get_property;
object_class->set_property = meta_monitor_manager_set_property;
object_class->dispose = meta_monitor_manager_dispose;
object_class->finalize = meta_monitor_manager_finalize;
@ -371,8 +336,6 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
g_object_class_override_property (object_class, PROP_POWER_SAVE_MODE, "power-save-mode");
}
static const double known_diagonals[] = {

View File

@ -36,11 +36,24 @@
struct _MetaBackendNativePrivate
{
MetaLauncher *launcher;
GSettings *keyboard_settings;
};
typedef struct _MetaBackendNativePrivate MetaBackendNativePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaBackendNative, meta_backend_native, META_TYPE_BACKEND);
static void
meta_backend_native_finalize (GObject *object)
{
MetaBackendNative *native = META_BACKEND_NATIVE (object);
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
g_clear_object (&priv->keyboard_settings);
G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (object);
}
/*
* The pointer constrain code is mostly a rip-off of the XRandR code from Xorg.
* (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder)
@ -142,15 +155,46 @@ pointer_constrain_callback (ClutterInputDevice *device,
constrain_all_screen_monitors(device, monitors, n_monitors, new_x, new_y);
}
static void
set_keyboard_repeat (MetaBackendNative *native)
{
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
gboolean repeat;
unsigned int delay, interval;
repeat = g_settings_get_boolean (priv->keyboard_settings, "repeat");
delay = g_settings_get_uint (priv->keyboard_settings, "delay");
interval = g_settings_get_uint (priv->keyboard_settings, "repeat-interval");
clutter_evdev_set_keyboard_repeat (manager, repeat, delay, interval);
}
static void
keyboard_settings_changed (GSettings *settings,
const char *key,
gpointer data)
{
MetaBackendNative *native = data;
set_keyboard_repeat (native);
}
static void
meta_backend_native_post_init (MetaBackend *backend)
{
MetaBackendNative *native = META_BACKEND_NATIVE (backend);
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
META_BACKEND_CLASS (meta_backend_native_parent_class)->post_init (backend);
clutter_evdev_set_pointer_constrain_callback (manager, pointer_constrain_callback,
NULL, NULL);
priv->keyboard_settings = g_settings_new ("org.gnome.settings-daemon.peripherals.keyboard");
g_signal_connect (priv->keyboard_settings, "changed",
G_CALLBACK (keyboard_settings_changed), native);
set_keyboard_repeat (native);
}
static MetaIdleMonitor *
@ -229,12 +273,16 @@ meta_backend_native_lock_layout_group (MetaBackend *backend,
{
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
clutter_evdev_set_keyboard_layout_index (manager, idx);
g_signal_emit_by_name (backend, "keymap-layout-group-changed", idx, 0);
}
static void
meta_backend_native_class_init (MetaBackendNativeClass *klass)
{
MetaBackendClass *backend_class = META_BACKEND_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_backend_native_finalize;
backend_class->post_init = meta_backend_native_post_init;
backend_class->create_idle_monitor = meta_backend_native_create_idle_monitor;
@ -270,7 +318,7 @@ meta_activate_vt (int vt, GError **error)
* meta_activate_session:
*
* Tells mutter to activate the session. When mutter is a
* Wayland compositor, this tells logind to switch over to
* display server, this tells logind to switch over to
* the new session.
*/
gboolean

View File

@ -27,16 +27,27 @@
#include "meta-cursor-renderer-native.h"
#include <gbm.h>
#include <xf86drm.h>
#include "meta-cursor-private.h"
#include "meta-monitor-manager.h"
#ifndef DRM_CAP_CURSOR_WIDTH
#define DRM_CAP_CURSOR_WIDTH 0x8
#endif
#ifndef DRM_CAP_CURSOR_HEIGHT
#define DRM_CAP_CURSOR_HEIGHT 0x9
#endif
struct _MetaCursorRendererNativePrivate
{
gboolean has_hw_cursor;
int drm_fd;
struct gbm_device *gbm;
uint64_t cursor_width;
uint64_t cursor_height;
};
typedef struct _MetaCursorRendererNativePrivate MetaCursorRendererNativePrivate;
@ -71,17 +82,13 @@ set_crtc_cursor (MetaCursorRendererNative *native,
{
struct gbm_bo *bo;
union gbm_bo_handle handle;
int width, height;
int hot_x, hot_y;
bo = meta_cursor_reference_get_gbm_bo (cursor, &hot_x, &hot_y);
handle = gbm_bo_get_handle (bo);
width = gbm_bo_get_width (bo);
height = gbm_bo_get_height (bo);
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, handle.u32,
width, height, hot_x, hot_y);
priv->cursor_width, priv->cursor_height, hot_x, hot_y);
}
else
{
@ -186,6 +193,19 @@ meta_cursor_renderer_native_init (MetaCursorRendererNative *native)
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx));
priv->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
priv->gbm = gbm_create_device (priv->drm_fd);
uint64_t width, height;
if (drmGetCap (priv->drm_fd, DRM_CAP_CURSOR_WIDTH, &width) == 0 &&
drmGetCap (priv->drm_fd, DRM_CAP_CURSOR_HEIGHT, &height) == 0)
{
priv->cursor_width = width;
priv->cursor_height = height;
}
else
{
priv->cursor_width = 64;
priv->cursor_height = 64;
}
}
#endif
}
@ -198,6 +218,16 @@ meta_cursor_renderer_native_get_gbm_device (MetaCursorRendererNative *native)
return priv->gbm;
}
void
meta_cursor_renderer_native_get_cursor_size (MetaCursorRendererNative *native,
uint64_t *width, uint64_t *height)
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
*width = priv->cursor_width;
*height = priv->cursor_height;
}
void
meta_cursor_renderer_native_force_update (MetaCursorRendererNative *native)
{

View File

@ -50,6 +50,7 @@ struct _MetaCursorRendererNativeClass
GType meta_cursor_renderer_native_get_type (void) G_GNUC_CONST;
struct gbm_device * meta_cursor_renderer_native_get_gbm_device (MetaCursorRendererNative *renderer);
void meta_cursor_renderer_native_get_cursor_size (MetaCursorRendererNative *native, uint64_t *width, uint64_t *height);
void meta_cursor_renderer_native_force_update (MetaCursorRendererNative *renderer);
#endif /* META_CURSOR_RENDERER_NATIVE_H */

View File

@ -65,9 +65,14 @@ struct _MetaBackendX11Private
uint8_t xkb_error_base;
struct xkb_keymap *keymap;
gchar *keymap_layouts;
gchar *keymap_variants;
gchar *keymap_options;
};
typedef struct _MetaBackendX11Private MetaBackendX11Private;
static void apply_keymap (MetaBackendX11 *x11);
G_DEFINE_TYPE_WITH_PRIVATE (MetaBackendX11, meta_backend_x11, META_TYPE_BACKEND);
static void
@ -326,6 +331,17 @@ take_touch_grab (MetaBackend *backend)
False, &mask, 1, &mods);
}
static void
on_device_added (ClutterDeviceManager *device_manager,
ClutterInputDevice *device,
gpointer user_data)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (user_data);
if (clutter_input_device_get_device_type (device) == CLUTTER_KEYBOARD_DEVICE)
apply_keymap (x11);
}
static void
meta_backend_x11_post_init (MetaBackend *backend)
{
@ -376,6 +392,9 @@ meta_backend_x11_post_init (MetaBackend *backend)
meta_fatal ("X server doesn't have the XKB extension, version %d.%d or newer\n",
XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION);
g_signal_connect_object (clutter_device_manager_get_default (), "device-added",
G_CALLBACK (on_device_added), backend, 0);
META_BACKEND_CLASS (meta_backend_x11_parent_class)->post_init (backend);
}
@ -560,21 +579,22 @@ upload_xkb_description (Display *xdisplay,
}
static void
meta_backend_x11_set_keymap (MetaBackend *backend,
const char *layouts,
const char *variants,
const char *options)
apply_keymap (MetaBackendX11 *x11)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
XkbRF_RulesRec *xkb_rules;
XkbRF_VarDefsRec xkb_var_defs = { 0 };
gchar *rules_file_path;
if (!priv->keymap_layouts ||
!priv->keymap_variants ||
!priv->keymap_options)
return;
get_xkbrf_var_defs (priv->xdisplay,
layouts,
variants,
options,
priv->keymap_layouts,
priv->keymap_variants,
priv->keymap_options,
&rules_file_path,
&xkb_var_defs);
@ -598,6 +618,25 @@ meta_backend_x11_set_keymap (MetaBackend *backend,
g_free (rules_file_path);
}
static void
meta_backend_x11_set_keymap (MetaBackend *backend,
const char *layouts,
const char *variants,
const char *options)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
g_free (priv->keymap_layouts);
priv->keymap_layouts = g_strdup (layouts);
g_free (priv->keymap_variants);
priv->keymap_variants = g_strdup (variants);
g_free (priv->keymap_options);
priv->keymap_options = g_strdup (options);
apply_keymap (x11);
}
static struct xkb_keymap *
meta_backend_x11_get_keymap (MetaBackend *backend)
{
@ -631,10 +670,20 @@ static void
meta_backend_x11_update_screen_size (MetaBackend *backend,
int width, int height)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
Window xwin = meta_backend_x11_get_xwindow (x11);
XResizeWindow (priv->xdisplay, xwin, width, height);
if (meta_is_wayland_compositor ())
{
/* For a nested wayland session, we want to go through Clutter to update the
* toplevel window size, rather than doing it directly.
*/
META_BACKEND_CLASS (meta_backend_x11_parent_class)->update_screen_size (backend, width, height);
}
else
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
Window xwin = meta_backend_x11_get_xwindow (x11);
XResizeWindow (priv->xdisplay, xwin, width, height);
}
}
static void

View File

@ -140,11 +140,35 @@ meta_monitor_transform_from_xrandr_all (Rotation rotation)
return ret;
}
static gboolean
output_get_property_exists (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output, const char *propname)
{
gboolean exists = FALSE;
Atom atom, actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *buffer;
atom = XInternAtom (manager_xrandr->xdisplay, propname, False);
XRRGetOutputProperty (manager_xrandr->xdisplay,
(XID)output->winsys_id,
atom,
0, G_MAXLONG, False, False, AnyPropertyType,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
exists = (actual_type != None);
XFree (buffer);
return exists;
}
static gboolean
output_get_boolean_property (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output, const char *propname)
{
gboolean value;
gboolean value = FALSE;
Atom atom, actual_type;
int actual_format;
unsigned long nitems, bytes_after;
@ -158,12 +182,12 @@ output_get_boolean_property (MetaMonitorManagerXrandr *manager_xrandr,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
if (actual_type != XA_CARDINAL || actual_format != 32 ||
nitems < 1)
return FALSE;
if (actual_type != XA_CARDINAL || actual_format != 32 || nitems < 1)
goto out;
value = ((int*)buffer)[0];
out:
XFree (buffer);
return value;
}
@ -187,7 +211,7 @@ static int
output_get_backlight_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output)
{
gboolean value;
int value = -1;
Atom atom, actual_type;
int actual_format;
unsigned long nitems, bytes_after;
@ -201,14 +225,17 @@ output_get_backlight_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
if (actual_type != XA_INTEGER || actual_format != 32 ||
nitems < 1)
return -1;
if (actual_type != XA_INTEGER || actual_format != 32 || nitems < 1)
goto out;
value = ((int*)buffer)[0];
out:
XFree (buffer);
return normalize_backlight (output, value);
if (value > 0)
return normalize_backlight (output, value);
else
return -1;
}
static void
@ -327,7 +354,7 @@ static gboolean
output_get_hotplug_mode_update (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output)
{
return output_get_boolean_property (manager_xrandr, output, "hotplug_mode_update");
return output_get_property_exists (manager_xrandr, output, "hotplug_mode_update");
}
static char *
@ -811,26 +838,12 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
unsigned int j, n_outputs;
int width, height;
Status ok;
unsigned long old_controlled_mask;
unsigned long new_controlled_mask;
mode = crtc_info->mode;
n_outputs = crtc_info->outputs->len;
outputs = g_new (XID, n_outputs);
old_controlled_mask = 0;
for (j = 0; j < manager->n_outputs; j++)
{
MetaOutput *output;
output = &manager->outputs[j];
if (output->crtc == crtc)
old_controlled_mask |= 1UL << j;
}
new_controlled_mask = 0;
for (j = 0; j < n_outputs; j++)
{
MetaOutput *output;
@ -839,21 +852,10 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
output->is_dirty = TRUE;
output->crtc = crtc;
new_controlled_mask |= 1UL << j;
outputs[j] = output->winsys_id;
}
if (crtc->current_mode == mode &&
crtc->rect.x == crtc_info->x &&
crtc->rect.y == crtc_info->y &&
crtc->transform == crtc_info->transform &&
old_controlled_mask == new_controlled_mask)
{
/* No change */
goto next;
}
ok = XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
@ -1072,6 +1074,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
gboolean new_config;
gboolean applied_config = FALSE;
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
return FALSE;
@ -1088,39 +1091,32 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
manager->serial++;
meta_monitor_manager_xrandr_read_current (manager);
new_config = manager_xrandr->resources->timestamp >=
manager_xrandr->resources->configTimestamp;
if (meta_monitor_manager_has_hotplug_mode_update (manager))
new_config = manager_xrandr->resources->timestamp >= manager_xrandr->resources->configTimestamp;
/* If this is the X server telling us we set a new configuration,
* we can simply short-cut to rebuilding our logical configuration.
*/
if (new_config)
{
/* Check if the current intended configuration is a result of an
XRandR call. Otherwise, hotplug_mode_update tells us to get
a new preferred mode on hotplug events to handle dynamic
guest resizing. */
if (new_config)
meta_monitor_manager_xrandr_rebuild_derived (manager);
else
meta_monitor_config_make_default (manager->config, manager);
}
else
{
/* 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 qxl and vbox drivers). */
if (new_config || meta_monitor_config_match_current (manager->config, manager))
meta_monitor_manager_xrandr_rebuild_derived (manager);
else if (!meta_monitor_config_apply_stored (manager->config, manager))
meta_monitor_config_make_default (manager->config, manager);
meta_monitor_manager_xrandr_rebuild_derived (manager);
goto out;
}
/* If the monitor has hotplug_mode_update (which is used by VMs), don't bother
* applying our stored configuration, because it's likely the user just resizing
* the window.
*/
if (!meta_monitor_manager_has_hotplug_mode_update (manager))
{
if (meta_monitor_config_apply_stored (manager->config, manager))
applied_config = TRUE;
}
/* If we haven't applied any configuration, apply the default configuration. */
if (!applied_config)
meta_monitor_config_make_default (manager->config, manager);
out:
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);

View File

@ -51,6 +51,12 @@ round_to_fixed (float x)
return roundf (x * 256);
}
/* Help macros to scale from OpenGL <-1,1> coordinates system to
* window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c
*/
#define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
/* This helper function checks if (according to our fixed point precision)
* the vertices @verts form a box of width @widthf and height @heightf
* located at integral coordinates. These coordinates are returned
@ -118,3 +124,67 @@ meta_actor_is_untransformed (ClutterActor *actor,
return meta_actor_vertices_are_untransformed (verts, widthf, heightf, x_origin, y_origin);
}
/**
* meta_actor_painting_untransformed:
* @paint_width: the width of the painted area
* @paint_height: the height of the painted area
* @x_origin: if the transform is only an integer translation
* then the X coordinate of the location of the origin under the transformation
* from drawing space to screen pixel space is returned here.
* @y_origin: if the transform is only an integer translation
* then the X coordinate of the location of the origin under the transformation
* from drawing space to screen pixel space is returned here.
*
* Determines if the current painting transform is an integer translation.
* This can differ from the result of meta_actor_is_untransformed() when
* painting an actor if we're inside a inside a clone paint. @paint_width
* and @paint_height are used to determine the vertices of the rectangle
* we check to see if the painted area is "close enough" to the integer
* transform.
*/
gboolean
meta_actor_painting_untransformed (int paint_width,
int paint_height,
int *x_origin,
int *y_origin)
{
CoglMatrix modelview, projection, modelview_projection;
ClutterVertex vertices[4];
float viewport[4];
int i;
cogl_get_modelview_matrix (&modelview);
cogl_get_projection_matrix (&projection);
cogl_matrix_multiply (&modelview_projection,
&projection,
&modelview);
vertices[0].x = 0;
vertices[0].y = 0;
vertices[0].z = 0;
vertices[1].x = paint_width;
vertices[1].y = 0;
vertices[1].z = 0;
vertices[2].x = 0;
vertices[2].y = paint_height;
vertices[2].z = 0;
vertices[3].x = paint_width;
vertices[3].y = paint_height;
vertices[3].z = 0;
cogl_get_viewport (viewport);
for (i = 0; i < 4; i++)
{
float w = 1;
cogl_matrix_transform_point (&modelview_projection, &vertices[i].x, &vertices[i].y, &vertices[i].z, &w);
vertices[i].x = MTX_GL_SCALE_X (vertices[i].x, w,
viewport[2], viewport[0]);
vertices[i].y = MTX_GL_SCALE_Y (vertices[i].y, w,
viewport[3], viewport[1]);
}
return meta_actor_vertices_are_untransformed (vertices, paint_width, paint_height, x_origin, y_origin);
}

View File

@ -31,4 +31,9 @@ gboolean meta_actor_is_untransformed (ClutterActor *actor,
int *x_origin,
int *y_origin);
gboolean meta_actor_painting_untransformed (int paint_width,
int paint_height,
int *x_origin,
int *y_origin);
#endif /* __META_CLUTTER_UTILS_H__ */

View File

@ -64,3 +64,78 @@ meta_create_texture_pipeline (CoglTexture *src_texture)
return pipeline;
}
static gboolean is_pot(int x)
{
return x > 0 && (x & (x - 1)) == 0;
}
/**
* meta_create_texture:
* @width: width of the texture to create
* @height: height of the texture to create
* @components; components to store in the texture (color or alpha)
* @flags: flags that affect the allocation behavior
*
* Creates a texture of the given size with the specified components
* for use as a frame buffer object.
*
* If non-power-of-two textures are not supported on the system, then
* the texture will be created as a texture rectangle; in this case,
* hardware repeating isn't possible, and texture coordinates are also
* different, but Cogl hides these issues from the application, except from
* GLSL shaders. Since GLSL is never (or at least almost never)
* present on such a system, this is not typically an issue.
*
* If %META_TEXTURE_ALLOW_SLICING is present in @flags, and the texture
* is larger than the texture size limits of the system, then the texture
* will be created as a sliced texture. This also will cause problems
* with using the texture with GLSL, and is more likely to be an issue
* since all GL implementations have texture size limits, and they can
* be as small as 2048x2048 on reasonably current systems.
*/
CoglTexture *
meta_create_texture (int width,
int height,
CoglTextureComponents components,
MetaTextureFlags flags)
{
ClutterBackend *backend = clutter_get_default_backend ();
CoglContext *ctx = clutter_backend_get_cogl_context (backend);
CoglTexture *texture;
gboolean should_use_rectangle = FALSE;
if (!(is_pot (width) && is_pot (height)) &&
!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT))
{
if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE))
should_use_rectangle = TRUE;
else
g_error ("Cannot create texture. Support for GL_ARB_texture_non_power_of_two or "
"ARB_texture_rectangle is required");
}
if (should_use_rectangle)
texture = COGL_TEXTURE (cogl_texture_rectangle_new_with_size (ctx, width, height));
else
texture = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, width, height));
cogl_texture_set_components (texture, components);
if ((flags & META_TEXTURE_ALLOW_SLICING) != 0)
{
/* To find out if we need to slice the texture, we have to go ahead and force storage
* to be allocated
*/
CoglError *catch_error = NULL;
if (!cogl_texture_allocate (texture, &catch_error))
{
cogl_error_free (catch_error);
cogl_object_unref (texture);
texture = COGL_TEXTURE (cogl_texture_2d_sliced_new_with_size (ctx, width, height, COGL_TEXTURE_MAX_WASTE));
cogl_texture_set_components (texture, components);
}
}
return texture;
}

View File

@ -25,4 +25,14 @@
CoglPipeline * meta_create_texture_pipeline (CoglTexture *texture);
typedef enum {
META_TEXTURE_FLAGS_NONE = 0,
META_TEXTURE_ALLOW_SLICING = 1 << 1
} MetaTextureFlags;
CoglTexture *meta_create_texture (int width,
int height,
CoglTextureComponents components,
MetaTextureFlags flags);
#endif /* __META_COGL_UTILS_H__ */

View File

@ -23,7 +23,7 @@ struct _MetaCompositor
guint server_time_is_monotonic_time : 1;
guint no_mipmaps : 1;
ClutterActor *stage, *window_group, *top_window_group;
ClutterActor *stage, *window_group, *top_window_group, *feedback_group;
ClutterActor *background_actor;
GList *windows;
Window output;

View File

@ -185,6 +185,19 @@ meta_get_top_window_group_for_screen (MetaScreen *screen)
return compositor->top_window_group;
}
/**
* meta_get_feedback_group_for_screen:
* @screen: a #MetaScreen
*
* Returns: (transfer none): The feedback group corresponding to @screen
*/
ClutterActor *
meta_get_feedback_group_for_screen (MetaScreen *screen)
{
MetaCompositor *compositor = get_compositor_for_screen (screen);
return compositor->feedback_group;
}
/**
* meta_get_window_actors:
* @screen: a #MetaScreen
@ -478,9 +491,11 @@ meta_compositor_manage (MetaCompositor *compositor)
compositor->window_group = meta_window_group_new (screen);
compositor->top_window_group = meta_window_group_new (screen);
compositor->feedback_group = meta_window_group_new (screen);
clutter_actor_add_child (compositor->stage, compositor->window_group);
clutter_actor_add_child (compositor->stage, compositor->top_window_group);
clutter_actor_add_child (compositor->stage, compositor->feedback_group);
if (meta_is_wayland_compositor ())
{
@ -920,7 +935,7 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
old_actor = old_stack->data;
old_window = meta_window_actor_get_meta_window (old_actor);
if (old_window->hidden &&
if ((old_window->hidden || old_window->unmanaging) &&
!meta_window_actor_effect_in_progress (old_actor))
{
old_stack = g_list_delete_link (old_stack, old_stack);
@ -954,7 +969,7 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
* filtered out non-animating hidden windows above.
*/
if (old_actor &&
(!stack_actor || old_window->hidden))
(!stack_actor || old_window->hidden || old_window->unmanaging))
{
actor = old_actor;
window = old_window;

View File

@ -1,7 +1,7 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright 2009 Sander Dijkhuis
* Copyright 2010 Red Hat, Inc.
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@ -26,23 +26,122 @@
*
*/
#include <config.h>
/*
* The overall model drawing model of this widget is that we have one
* texture, or two interpolated textures, possibly with alpha or
* margins that let the underlying background show through, blended
* over a solid color or a gradient. The result of that combination
* can then be affected by a "vignette" that darkens the background
* away from a central point (or as a no-GLSL fallback, simply darkens
* the background) and by overall opacity.
*
* As of GNOME 3.14, GNOME is only using a fraction of this when the
* user sets the background through the control center - what can be
* set is:
*
* A single image without a border
* An animation of images without a border that blend together,
* with the blend changing every 4-5 minutes
* A solid color with a repeated noise texture blended over it
*
* This all is pretty easy to do in a fragment shader, except when:
*
* A) We don't have GLSL - in this case, the operation of
* interpolating the two textures and blending the result over the
* background can't be expressed with Cogl's fixed-function layer
* combining (which is confined to what GL's texture environment
* combining can do) So we can only handle the above directly if
* there are no margins or alpha.
*
* B) The image textures are sliced. Texture size limits on older
* hardware (pre-965 intel hardware, r300, etc.) is often 2048,
* and it would be common to use a texture larger than this for a
* background and expect it to be scaled down. Cogl can compensate
* for this by breaking the texture up into multiple textures, but
* can't multitexture with sliced textures. So we can only handle
* the above if there's a single texture.
*
* However, even when we *can* represent everything in a single pass,
* it's not necessarily efficient. If we want to draw a 1024x768
* background, it's pretty inefficient to bilinearly texture from
* two 2560x1440 images and mix that. So the drawing model we take
* here is that MetaBackground generates a single texture (which
* might be a 1x1 texture for a solid color, or a 1x2 texture for a
* gradient, or a repeated texture for wallpaper, or a pre-rendered
* texture the size of the screen), and we draw with that, possibly
* adding the vignette and opacity.
*/
#include <cogl/cogl-texture-pixmap-x11.h>
#include <config.h>
#include <clutter/clutter.h>
#include <X11/Xatom.h>
#include "cogl-utils.h"
#include "compositor-private.h"
#include "clutter-utils.h"
#include <meta/errors.h>
#include <meta/meta-background.h>
#include "meta-background-actor-private.h"
#include "meta-background-private.h"
#include "meta-cullable.h"
enum
{
PROP_META_SCREEN = 1,
PROP_MONITOR,
PROP_BACKGROUND,
PROP_VIGNETTE,
PROP_VIGNETTE_SHARPNESS,
PROP_BRIGHTNESS
};
typedef enum {
CHANGED_BACKGROUND = 1 << 0,
CHANGED_EFFECTS = 1 << 2,
CHANGED_VIGNETTE_PARAMETERS = 1 << 3,
CHANGED_ALL = 0xFFFF
} ChangedFlags;
#define VERTEX_SHADER_DECLARATIONS \
"uniform vec2 scale;\n" \
"uniform vec2 offset;\n" \
"varying vec2 position;\n" \
#define VERTEX_SHADER_CODE \
"position = cogl_tex_coord0_in.xy * scale + offset;\n" \
#define FRAGMENT_SHADER_DECLARATIONS \
"uniform float vignette_sharpness;\n" \
"varying vec2 position;\n" \
#define FRAGMENT_SHADER_CODE \
"float t = 2.0 * length(position);\n" \
"t = min(t, 1.0);\n" \
"float pixel_brightness = 1 - t * vignette_sharpness;\n" \
"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \
typedef struct _MetaBackgroundLayer MetaBackgroundLayer;
typedef enum {
PIPELINE_VIGNETTE = (1 << 0),
PIPELINE_BLEND = (1 << 1),
} PipelineFlags;
struct _MetaBackgroundActorPrivate
{
MetaScreen *screen;
int monitor;
MetaBackground *background;
gboolean vignette;
double brightness;
double vignette_sharpness;
ChangedFlags changed;
CoglPipeline *pipeline;
PipelineFlags pipeline_flags;
cairo_rectangle_int_t texture_area;
gboolean force_bilinear;
cairo_region_t *clip_region;
};
@ -66,27 +165,45 @@ static void
meta_background_actor_dispose (GObject *object)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
MetaBackgroundActorPrivate *priv = self->priv;
set_clip_region (self, NULL);
meta_background_actor_set_background (self, NULL);
if (priv->pipeline)
{
cogl_object_unref (priv->pipeline);
priv->pipeline = NULL;
}
G_OBJECT_CLASS (meta_background_actor_parent_class)->dispose (object);
}
static void
get_preferred_size (MetaBackgroundActor *self,
gfloat *width,
gfloat *height)
{
MetaBackgroundActorPrivate *priv = META_BACKGROUND_ACTOR (self)->priv;
MetaRectangle monitor_geometry;
meta_screen_get_monitor_geometry (priv->screen, priv->monitor, &monitor_geometry);
if (width != NULL)
*width = monitor_geometry.width;
if (height != NULL)
*height = monitor_geometry.height;
}
static void
meta_background_actor_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ClutterContent *content;
gfloat width;
content = clutter_actor_get_content (actor);
if (content)
clutter_content_get_preferred_size (content, &width, NULL);
else
width = 0;
get_preferred_size (META_BACKGROUND_ACTOR (actor), &width, NULL);
if (min_width_p)
*min_width_p = width;
@ -101,15 +218,9 @@ meta_background_actor_get_preferred_height (ClutterActor *actor,
gfloat *natural_height_p)
{
ClutterContent *content;
gfloat height;
content = clutter_actor_get_content (actor);
if (content)
clutter_content_get_preferred_size (content, NULL, &height);
else
height = 0;
get_preferred_size (META_BACKGROUND_ACTOR (actor), NULL, &height);
if (min_height_p)
*min_height_p = height;
@ -117,43 +228,430 @@ meta_background_actor_get_preferred_height (ClutterActor *actor,
*natural_height_p = height;
}
static CoglPipeline *
make_pipeline (PipelineFlags pipeline_flags)
{
static CoglPipeline *templates[4];
CoglPipeline **templatep;
templatep = &templates[pipeline_flags];
if (*templatep == NULL)
{
/* Cogl automatically caches pipelines with no eviction policy,
* so we need to prevent identical pipelines from getting cached
* separately, by reusing the same shader snippets.
*/
*templatep = COGL_PIPELINE (meta_create_texture_pipeline (NULL));
if ((pipeline_flags & PIPELINE_VIGNETTE) != 0)
{
static CoglSnippet *vertex_snippet;
static CoglSnippet *fragment_snippet;
if (!vertex_snippet)
vertex_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
VERTEX_SHADER_DECLARATIONS, VERTEX_SHADER_CODE);
cogl_pipeline_add_snippet (*templatep, vertex_snippet);
if (!fragment_snippet)
fragment_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
FRAGMENT_SHADER_DECLARATIONS, FRAGMENT_SHADER_CODE);
cogl_pipeline_add_snippet (*templatep, fragment_snippet);
}
if ((pipeline_flags & PIPELINE_BLEND) == 0)
cogl_pipeline_set_blend (*templatep, "RGBA = ADD (SRC_COLOR, 0)", NULL);
}
return cogl_pipeline_copy (*templatep);
}
static void
setup_pipeline (MetaBackgroundActor *self,
cairo_rectangle_int_t *actor_pixel_rect)
{
MetaBackgroundActorPrivate *priv = self->priv;
PipelineFlags pipeline_flags = 0;
guint8 opacity;
float color_component;
CoglPipelineFilter filter;
opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self));
if (opacity < 255)
pipeline_flags |= PIPELINE_BLEND;
if (priv->vignette && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
pipeline_flags |= PIPELINE_VIGNETTE;
if (priv->pipeline &&
pipeline_flags != priv->pipeline_flags)
{
cogl_object_unref (priv->pipeline);
priv->pipeline = NULL;
}
if (priv->pipeline == NULL)
{
priv->pipeline_flags = pipeline_flags;
priv->pipeline = make_pipeline (pipeline_flags);
priv->changed = CHANGED_ALL;
}
if ((priv->changed & CHANGED_BACKGROUND) != 0)
{
CoglPipelineWrapMode wrap_mode;
CoglTexture *texture = meta_background_get_texture (priv->background,
priv->monitor,
&priv->texture_area,
&wrap_mode);
priv->force_bilinear = texture &&
(priv->texture_area.width != (int)cogl_texture_get_width (texture) ||
priv->texture_area.height != (int)cogl_texture_get_height (texture));
cogl_pipeline_set_layer_texture (priv->pipeline, 0, texture);
cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0, wrap_mode);
}
if ((priv->changed & CHANGED_VIGNETTE_PARAMETERS) != 0)
{
cogl_pipeline_set_uniform_1f (priv->pipeline,
cogl_pipeline_get_uniform_location (priv->pipeline,
"vignette_sharpness"),
priv->vignette_sharpness);
}
if (priv->vignette)
{
color_component = priv->brightness * opacity / 255.;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
/* Darken everything to match the average brightness that would
* be there if we were drawing the vignette, which is
* (1 - (pi/12.) * vignette_sharpness) [exercise for the reader :]
*/
color_component *= (1 - 0.74 * priv->vignette_sharpness);
}
}
else
color_component = opacity / 255.;
cogl_pipeline_set_color4f (priv->pipeline,
color_component,
color_component,
color_component,
opacity / 255.);
if (!priv->force_bilinear &&
meta_actor_painting_untransformed (actor_pixel_rect->width, actor_pixel_rect->height, NULL, NULL))
filter = COGL_PIPELINE_FILTER_NEAREST;
else
filter = COGL_PIPELINE_FILTER_LINEAR;
cogl_pipeline_set_layer_filters (priv->pipeline, 0, filter, filter);
}
static void
set_glsl_parameters (MetaBackgroundActor *self,
cairo_rectangle_int_t *actor_pixel_rect)
{
MetaBackgroundActorPrivate *priv = self->priv;
float scale[2];
float offset[2];
/* Compute a scale and offset for transforming texture coordinates to the
* coordinate system from [-0.5 to 0.5] across the area of the actor
*/
scale[0] = priv->texture_area.width / (float)actor_pixel_rect->width;
scale[1] = priv->texture_area.height / (float)actor_pixel_rect->height;
offset[0] = priv->texture_area.x / (float)actor_pixel_rect->width - 0.5;
offset[1] = priv->texture_area.y / (float)actor_pixel_rect->height - 0.5;
cogl_pipeline_set_uniform_float (priv->pipeline,
cogl_pipeline_get_uniform_location (priv->pipeline,
"scale"),
2, 1, scale);
cogl_pipeline_set_uniform_float (priv->pipeline,
cogl_pipeline_get_uniform_location (priv->pipeline,
"offset"),
2, 1, offset);
}
static void
paint_clipped_rectangle (CoglFramebuffer *fb,
CoglPipeline *pipeline,
cairo_rectangle_int_t *rect,
cairo_rectangle_int_t *texture_area)
{
float x1, y1, x2, y2;
float tx1, ty1, tx2, ty2;
x1 = rect->x;
y1 = rect->y;
x2 = rect->x + rect->width;
y2 = rect->y + rect->height;
tx1 = (x1 - texture_area->x) / texture_area->width;
ty1 = (y1 - texture_area->y) / texture_area->height;
tx2 = (x2 - texture_area->x) / texture_area->width;
ty2 = (y2 - texture_area->y) / texture_area->height;
cogl_framebuffer_draw_textured_rectangle (fb, pipeline,
x1, y1, x2, y2,
tx1, ty1, tx2, ty2);
}
static gboolean
meta_background_actor_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
return clutter_paint_volume_set_from_allocation (volume, actor);
}
static void
meta_background_actor_paint (ClutterActor *actor)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
MetaBackgroundActorPrivate *priv = self->priv;
ClutterActorBox actor_box;
cairo_rectangle_int_t actor_pixel_rect;
CoglFramebuffer *fb;
int i;
if ((priv->clip_region && cairo_region_is_empty (priv->clip_region)))
return;
clutter_actor_get_content_box (actor, &actor_box);
actor_pixel_rect.x = actor_box.x1;
actor_pixel_rect.y = actor_box.y1;
actor_pixel_rect.width = actor_box.x2 - actor_box.x1;
actor_pixel_rect.height = actor_box.y2 - actor_box.y1;
setup_pipeline (self, &actor_pixel_rect);
set_glsl_parameters (self, &actor_pixel_rect);
/* Limit to how many separate rectangles we'll draw; beyond this just
* fall back and draw the whole thing */
#define MAX_RECTS 64
fb = cogl_get_draw_framebuffer ();
/* Now figure out what to actually paint.
*/
if (priv->clip_region != NULL)
{
int n_rects = cairo_region_num_rectangles (priv->clip_region);
if (n_rects <= MAX_RECTS)
{
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (priv->clip_region, i, &rect);
if (!gdk_rectangle_intersect (&actor_pixel_rect, &rect, &rect))
continue;
paint_clipped_rectangle (fb, priv->pipeline, &rect, &priv->texture_area);
}
return;
}
}
paint_clipped_rectangle (fb, priv->pipeline, &actor_pixel_rect, &priv->texture_area);
}
static void
meta_background_actor_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
MetaBackgroundActorPrivate *priv = self->priv;
switch (prop_id)
{
case PROP_META_SCREEN:
priv->screen = g_value_get_object (value);
break;
case PROP_MONITOR:
priv->monitor = g_value_get_int (value);
break;
case PROP_BACKGROUND:
meta_background_actor_set_background (self, g_value_get_object (value));
break;
case PROP_VIGNETTE:
meta_background_actor_set_vignette (self,
g_value_get_boolean (value),
priv->brightness,
priv->vignette_sharpness);
break;
case PROP_VIGNETTE_SHARPNESS:
meta_background_actor_set_vignette (self,
priv->vignette,
priv->brightness,
g_value_get_double (value));
break;
case PROP_BRIGHTNESS:
meta_background_actor_set_vignette (self,
priv->vignette,
g_value_get_double (value),
priv->vignette_sharpness);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_background_actor_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaBackgroundActorPrivate *priv = META_BACKGROUND_ACTOR (object)->priv;
switch (prop_id)
{
case PROP_META_SCREEN:
g_value_set_object (value, priv->screen);
break;
case PROP_MONITOR:
g_value_set_int (value, priv->monitor);
break;
case PROP_BACKGROUND:
g_value_set_object (value, priv->background);
break;
case PROP_VIGNETTE:
g_value_set_boolean (value, priv->vignette);
break;
case PROP_BRIGHTNESS:
g_value_set_double (value, priv->brightness);
break;
case PROP_VIGNETTE_SHARPNESS:
g_value_set_double (value, priv->vignette_sharpness);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_background_actor_class_init (MetaBackgroundActorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
GParamSpec *param_spec;
g_type_class_add_private (klass, sizeof (MetaBackgroundActorPrivate));
object_class->dispose = meta_background_actor_dispose;
object_class->set_property = meta_background_actor_set_property;
object_class->get_property = meta_background_actor_get_property;
actor_class->get_preferred_width = meta_background_actor_get_preferred_width;
actor_class->get_preferred_height = meta_background_actor_get_preferred_height;
actor_class->get_paint_volume = meta_background_actor_get_paint_volume;
actor_class->paint = meta_background_actor_paint;
param_spec = g_param_spec_object ("meta-screen",
"MetaScreen",
"MetaScreen",
META_TYPE_SCREEN,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class,
PROP_META_SCREEN,
param_spec);
param_spec = g_param_spec_int ("monitor",
"monitor",
"monitor",
0, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class,
PROP_MONITOR,
param_spec);
param_spec = g_param_spec_object ("background",
"Background",
"MetaBackground object holding background parameters",
META_TYPE_BACKGROUND,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_BACKGROUND,
param_spec);
param_spec = g_param_spec_boolean ("vignette",
"Vignette",
"Whether vignette effect is enabled",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_VIGNETTE,
param_spec);
param_spec = g_param_spec_double ("brightness",
"Brightness",
"Brightness of vignette effect",
0.0, 1.0, 1.0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_BRIGHTNESS,
param_spec);
param_spec = g_param_spec_double ("vignette-sharpness",
"Vignette Sharpness",
"Sharpness of vignette effect",
0.0, G_MAXDOUBLE, 0.0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_VIGNETTE_SHARPNESS,
param_spec);
}
static void
meta_background_actor_init (MetaBackgroundActor *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
META_TYPE_BACKGROUND_ACTOR,
MetaBackgroundActorPrivate);
MetaBackgroundActorPrivate *priv;
priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
META_TYPE_BACKGROUND_ACTOR,
MetaBackgroundActorPrivate);
priv->vignette = FALSE;
priv->brightness = 1.0;
priv->vignette_sharpness = 0.0;
}
/**
* meta_background_actor_new:
* @monitor: Index of the monitor for which to draw the background
*
* Creates a new actor to draw the background for the given monitor.
* This actor should be associated with a #MetaBackground using
* clutter_actor_set_content()
*
* Return value: the newly created background actor
*/
ClutterActor *
meta_background_actor_new (void)
meta_background_actor_new (MetaScreen *screen,
int monitor)
{
MetaBackgroundActor *self;
self = g_object_new (META_TYPE_BACKGROUND_ACTOR, NULL);
self = g_object_new (META_TYPE_BACKGROUND_ACTOR,
"meta-screen", screen,
"monitor", monitor,
NULL);
return CLUTTER_ACTOR (self);
}
@ -195,3 +693,90 @@ meta_background_actor_get_clip_region (MetaBackgroundActor *self)
MetaBackgroundActorPrivate *priv = self->priv;
return priv->clip_region;
}
static void
invalidate_pipeline (MetaBackgroundActor *self,
ChangedFlags changed)
{
MetaBackgroundActorPrivate *priv = self->priv;
priv->changed |= changed;
}
static void
on_background_changed (MetaBackground *background,
MetaBackgroundActor *self)
{
invalidate_pipeline (self, CHANGED_BACKGROUND);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
void
meta_background_actor_set_background (MetaBackgroundActor *self,
MetaBackground *background)
{
MetaBackgroundActorPrivate *priv;
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
g_return_if_fail (background == NULL || META_IS_BACKGROUND (background));
priv = self->priv;
if (background == priv->background)
return;
if (priv->background)
{
g_signal_handlers_disconnect_by_func (priv->background,
(gpointer)on_background_changed,
self);
g_object_unref (priv->background);
priv->background = NULL;
}
if (background)
{
priv->background = g_object_ref (background);
g_signal_connect (priv->background, "changed",
G_CALLBACK (on_background_changed), self);
}
invalidate_pipeline (self, CHANGED_BACKGROUND);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
void
meta_background_actor_set_vignette (MetaBackgroundActor *self,
gboolean enabled,
double brightness,
double sharpness)
{
MetaBackgroundActorPrivate *priv;
gboolean changed = FALSE;
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
g_return_if_fail (brightness >= 0. && brightness <= 1.);
g_return_if_fail (sharpness >= 0.);
priv = self->priv;
enabled = enabled != FALSE;
if (enabled != priv->vignette)
{
priv->vignette = enabled;
invalidate_pipeline (self, CHANGED_EFFECTS);
changed = TRUE;
}
if (brightness != priv->brightness || sharpness != priv->vignette_sharpness)
{
priv->brightness = brightness;
priv->vignette_sharpness = sharpness;
invalidate_pipeline (self, CHANGED_VIGNETTE_PARAMETERS);
changed = TRUE;
}
if (changed)
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}

View File

@ -0,0 +1,347 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:meta-background-image
* @title: MetaBackgroundImage
* @short_description: objects holding images loaded from files, used for backgrounds
*/
#include <config.h>
#include <gio/gio.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <clutter/clutter.h>
#include <meta/meta-background-image.h>
#include "cogl-utils.h"
enum
{
LOADED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
struct _MetaBackgroundImageCache
{
GObject parent_instance;
GHashTable *images;
};
struct _MetaBackgroundImageCacheClass
{
GObjectClass parent_class;
};
struct _MetaBackgroundImage
{
GObject parent_instance;
char *filename;
MetaBackgroundImageCache *cache;
gboolean in_cache;
gboolean loaded;
CoglTexture *texture;
};
struct _MetaBackgroundImageClass
{
GObjectClass parent_class;
};
G_DEFINE_TYPE (MetaBackgroundImageCache, meta_background_image_cache, G_TYPE_OBJECT);
static void
meta_background_image_cache_init (MetaBackgroundImageCache *cache)
{
cache->images = g_hash_table_new (g_str_hash, g_str_equal);
}
static void
meta_background_image_cache_finalize (GObject *object)
{
MetaBackgroundImageCache *cache = META_BACKGROUND_IMAGE_CACHE (object);
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, cache->images);
while (g_hash_table_iter_next (&iter, &key, &value))
{
MetaBackgroundImage *image = value;
image->in_cache = FALSE;
}
g_hash_table_destroy (cache->images);
G_OBJECT_CLASS (meta_background_image_cache_parent_class)->finalize (object);
}
static void
meta_background_image_cache_class_init (MetaBackgroundImageCacheClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_background_image_cache_finalize;
}
/**
* meta_background_image_cache_get_default:
*
* Return value: (transfer none): the global singleton background cache
*/
MetaBackgroundImageCache *
meta_background_image_cache_get_default (void)
{
static MetaBackgroundImageCache *cache;
if (cache == NULL)
cache = g_object_new (META_TYPE_BACKGROUND_IMAGE_CACHE, NULL);
return cache;
}
static void
load_file (GTask *task,
MetaBackgroundImage *image,
gpointer task_data,
GCancellable *cancellable)
{
GError *error = NULL;
GdkPixbuf *pixbuf;
pixbuf = gdk_pixbuf_new_from_file (image->filename,
&error);
if (pixbuf == NULL)
{
g_task_return_error (task, error);
return;
}
g_task_return_pointer (task, pixbuf, (GDestroyNotify) g_object_unref);
}
static void
file_loaded (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
MetaBackgroundImage *image = META_BACKGROUND_IMAGE (source_object);
GError *error = NULL;
GTask *task;
CoglTexture *texture;
GdkPixbuf *pixbuf;
int width, height, row_stride;
guchar *pixels;
gboolean has_alpha;
task = G_TASK (result);
pixbuf = g_task_propagate_pointer (task, &error);
if (pixbuf == NULL)
{
g_warning ("Failed to load background '%s': %s",
image->filename, error->message);
g_clear_error (&error);
goto out;
}
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
row_stride = gdk_pixbuf_get_rowstride (pixbuf);
pixels = gdk_pixbuf_get_pixels (pixbuf);
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
texture = meta_create_texture (width, height,
has_alpha ? COGL_TEXTURE_COMPONENTS_RGBA : COGL_TEXTURE_COMPONENTS_RGB,
META_TEXTURE_ALLOW_SLICING);
if (!cogl_texture_set_data (texture,
has_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
row_stride,
pixels, 0,
NULL))
{
g_warning ("Failed to create texture for background");
cogl_object_unref (texture);
}
image->texture = texture;
out:
if (pixbuf != NULL)
g_object_unref (pixbuf);
image->loaded = TRUE;
g_signal_emit (image, signals[LOADED], 0);
}
/**
* meta_background_image_cache_load:
* @cache: a #MetaBackgroundImageCache
* @filename: filename to load
*
* Loads an image to use as a background, or returns a reference to an
* image that is already in the process of loading or loaded. In either
* case, what is returned is a #MetaBackgroundImage which can be derefenced
* to get a #CoglTexture. If meta_background_image_is_loaded() returns %TRUE,
* the background is loaded, otherwise the MetaBackgroundImage::loaded
* signal will be emitted exactly once. The 'loaded' state means that the
* loading process finished, whether it succeeded or failed.
*
* Return value: (transfer full): a #MetaBackgroundImage to dereference to get the loaded texture
*/
MetaBackgroundImage *
meta_background_image_cache_load (MetaBackgroundImageCache *cache,
const char *filename)
{
MetaBackgroundImage *image;
GTask *task;
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache), NULL);
g_return_val_if_fail (filename != NULL, NULL);
image = g_hash_table_lookup (cache->images, filename);
if (image != NULL)
return g_object_ref (image);
image = g_object_new (META_TYPE_BACKGROUND_IMAGE, NULL);
image->cache = cache;
image->in_cache = TRUE;
image->filename = g_strdup (filename);
g_hash_table_insert (cache->images, image->filename, image);
task = g_task_new (image, NULL, file_loaded, NULL);
g_task_run_in_thread (task, (GTaskThreadFunc) load_file);
g_object_unref (task);
return image;
}
/**
* meta_background_image_cache_purge:
* @cache: a #MetaBackgroundImageCache
* @filename: filename to remove from the cache
*
* Remove an entry from the cache; this would be used if monitoring
* showed that the file changed.
*/
void
meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
const char *filename)
{
MetaBackgroundImage *image;
g_return_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache));
g_return_if_fail (filename != NULL);
image = g_hash_table_lookup (cache->images, filename);
if (image == NULL)
return;
g_hash_table_remove (cache->images, image->filename);
image->in_cache = FALSE;
}
G_DEFINE_TYPE (MetaBackgroundImage, meta_background_image, G_TYPE_OBJECT);
static void
meta_background_image_init (MetaBackgroundImage *image)
{
}
static void
meta_background_image_finalize (GObject *object)
{
MetaBackgroundImage *image = META_BACKGROUND_IMAGE (object);
if (image->in_cache)
g_hash_table_remove (image->cache->images, image->filename);
if (image->texture)
cogl_object_unref (image->texture);
if (image->filename)
g_free (image->filename);
G_OBJECT_CLASS (meta_background_image_parent_class)->finalize (object);
}
static void
meta_background_image_class_init (MetaBackgroundImageClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_background_image_finalize;
signals[LOADED] =
g_signal_new ("loaded",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
/**
* meta_background_image_is_loaded:
* @image: a #MetaBackgroundImage
*
* Return value: %TRUE if loading has already completed, %FALSE otherwise
*/
gboolean
meta_background_image_is_loaded (MetaBackgroundImage *image)
{
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE (image), FALSE);
return image->loaded;
}
/**
* meta_background_image_get_success:
* @image: a #MetaBackgroundImage
*
* This function is a convenience function for checking for success,
* without having to call meta_background_image_get_texture() and
* handle the return of a Cogl type.
*
* Return value: %TRUE if loading completed successfully, otherwise %FALSE
*/
gboolean
meta_background_image_get_success (MetaBackgroundImage *image)
{
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE (image), FALSE);
return image->texture != NULL;
}
/**
* meta_background_image_get_texture:
* @image: a #MetaBackgroundImage
*
* Return value: (transfer none): a #CoglTexture if loading succeeded; if
* loading failed or has not yet finished, %NULL.
*/
CoglTexture *
meta_background_image_get_texture (MetaBackgroundImage *image)
{
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE (image), NULL);
return image->texture;
}

View File

@ -0,0 +1,15 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef META_BACKGROUND_PRIVATE_H
#define META_BACKGROUND_PRIVATE_H
#include <config.h>
#include "meta-background-private.h"
CoglTexture *meta_background_get_texture (MetaBackground *self,
int monitor_index,
cairo_rectangle_int_t *texture_area,
CoglPipelineWrapMode *wrap_mode);
#endif /* META_BACKGROUND_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* meta-dnd-actor-private.h: Actor for painting the DnD surface
*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_DND_ACTOR_PRIVATE_H
#define META_DND_ACTOR_PRIVATE_H
#include "meta-feedback-actor-private.h"
/**
* MetaDnDActor:
*
* This class handles the rendering of the DnD surface
*/
#define META_TYPE_DND_ACTOR (meta_dnd_actor_get_type ())
#define META_DND_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_DND_ACTOR, MetaDnDActor))
#define META_DND_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_DND_ACTOR, MetaDnDActorClass))
#define META_IS_DND_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_DND_ACTOR))
#define META_IS_DND_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_DND_ACTOR))
#define META_DND_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_DND_ACTOR, MetaDnDActorClass))
typedef struct _MetaDnDActor MetaDnDActor;
typedef struct _MetaDnDActorClass MetaDnDActorClass;
struct _MetaDnDActorClass
{
/*< private >*/
MetaFeedbackActorClass parent_class;
};
struct _MetaDnDActor
{
MetaFeedbackActor parent;
};
GType meta_dnd_actor_get_type (void);
ClutterActor *meta_dnd_actor_new (ClutterActor *drag_origin,
int start_x,
int start_y);
void meta_dnd_actor_drag_finish (MetaDnDActor *self,
gboolean success);
#endif /* META_DND_ACTOR_PRIVATE_H */

View File

@ -0,0 +1,231 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:meta-dnd-actor
* @title: MetaDnDActor
* @short_description: Actor for painting the drag and drop surface
*
*/
#include <config.h>
#include <clutter/clutter.h>
#include "meta-dnd-actor-private.h"
#define DRAG_FAILED_DURATION 500
enum {
PROP_DRAG_ORIGIN = 1,
PROP_DRAG_START_X,
PROP_DRAG_START_Y
};
typedef struct _MetaDnDActorPrivate MetaDnDActorPrivate;
struct _MetaDnDActorPrivate
{
ClutterActor *drag_origin;
int drag_start_x;
int drag_start_y;
};
G_DEFINE_TYPE_WITH_PRIVATE (MetaDnDActor, meta_dnd_actor, META_TYPE_FEEDBACK_ACTOR)
static void
meta_dnd_actor_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaDnDActor *self = META_DND_ACTOR (object);
MetaDnDActorPrivate *priv = meta_dnd_actor_get_instance_private (self);
switch (prop_id)
{
case PROP_DRAG_ORIGIN:
priv->drag_origin = g_value_get_object (value);
break;
case PROP_DRAG_START_X:
priv->drag_start_x = g_value_get_int (value);
break;
case PROP_DRAG_START_Y:
priv->drag_start_y = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_dnd_actor_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaDnDActor *self = META_DND_ACTOR (object);
MetaDnDActorPrivate *priv = meta_dnd_actor_get_instance_private (self);
switch (prop_id)
{
case PROP_DRAG_ORIGIN:
g_value_set_object (value, priv->drag_origin);
break;
case PROP_DRAG_START_X:
g_value_set_int (value, priv->drag_start_x);
break;
case PROP_DRAG_START_Y:
g_value_set_int (value, priv->drag_start_y);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_dnd_actor_class_init (MetaDnDActorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
object_class->set_property = meta_dnd_actor_set_property;
object_class->get_property = meta_dnd_actor_get_property;
pspec = g_param_spec_object ("drag-origin",
"Drag origin",
"The origin of the DnD operation",
CLUTTER_TYPE_ACTOR,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class,
PROP_DRAG_ORIGIN,
pspec);
pspec = g_param_spec_int ("drag-start-x",
"Drag start X",
"The X axis of the drag start point",
0, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class,
PROP_DRAG_START_X,
pspec);
pspec = g_param_spec_int ("drag-start-y",
"Drag start Y",
"The Y axis of the drag start point",
0, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class,
PROP_DRAG_START_Y,
pspec);
}
static void
meta_dnd_actor_init (MetaDnDActor *self)
{
}
/**
* meta_dnd_actor_new:
*
* Creates a new actor to draw the current drag and drop surface.
*
* Return value: the newly created background actor
*/
ClutterActor *
meta_dnd_actor_new (ClutterActor *drag_origin,
int drag_start_x,
int drag_start_y)
{
MetaDnDActor *self;
self = g_object_new (META_TYPE_DND_ACTOR,
"drag-origin", drag_origin,
"drag-start-x", drag_start_x,
"drag-start-y", drag_start_y,
NULL);
return CLUTTER_ACTOR (self);
}
static void
drag_failed_complete (ClutterTimeline *timeline,
gboolean is_finished,
gpointer user_data)
{
ClutterActor *self = user_data;
clutter_actor_remove_all_children (self);
clutter_actor_destroy (self);
}
void
meta_dnd_actor_drag_finish (MetaDnDActor *self,
gboolean success)
{
MetaDnDActorPrivate *priv;
ClutterActor *actor;
g_return_if_fail (META_IS_DND_ACTOR (self));
actor = CLUTTER_ACTOR (self);
priv = meta_dnd_actor_get_instance_private (self);
if (success)
{
clutter_actor_remove_all_children (CLUTTER_ACTOR (self));
clutter_actor_destroy (CLUTTER_ACTOR (self));
}
else
{
ClutterTransition *transition;
clutter_actor_save_easing_state (actor);
clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
clutter_actor_set_easing_duration (actor, DRAG_FAILED_DURATION);
clutter_actor_set_opacity (actor, 0);
if (CLUTTER_ACTOR_IS_VISIBLE (priv->drag_origin))
{
int anchor_x, anchor_y;
ClutterPoint dest;
clutter_actor_get_transformed_position (priv->drag_origin,
&dest.x, &dest.y);
meta_feedback_actor_get_anchor (META_FEEDBACK_ACTOR (self),
&anchor_x, &anchor_y);
dest.x += priv->drag_start_x - anchor_x;
dest.y += priv->drag_start_y - anchor_y;
clutter_actor_set_position (actor, dest.x, dest.y);
}
transition = clutter_actor_get_transition (actor, "opacity");
g_signal_connect (transition, "stopped",
G_CALLBACK (drag_failed_complete), self);
clutter_actor_restore_easing_state (actor);
}
}

View File

@ -0,0 +1,74 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* meta-feedback-actor-private.h: Actor for painting user interaction feedback
*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_FEEDBACK_ACTOR_PRIVATE_H
#define META_FEEDBACK_ACTOR_PRIVATE_H
#include <clutter/clutter.h>
/**
* MetaFeedbackActor:
*
* This class handles the rendering of user interaction feedback
*/
#define META_TYPE_FEEDBACK_ACTOR (meta_feedback_actor_get_type ())
#define META_FEEDBACK_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_FEEDBACK_ACTOR, MetaFeedbackActor))
#define META_FEEDBACK_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_FEEDBACK_ACTOR, MetaFeedbackActorClass))
#define META_IS_FEEDBACK_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_FEEDBACK_ACTOR))
#define META_IS_FEEDBACK_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_FEEDBACK_ACTOR))
#define META_FEEDBACK_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_FEEDBACK_ACTOR, MetaFeedbackActorClass))
typedef struct _MetaFeedbackActor MetaFeedbackActor;
typedef struct _MetaFeedbackActorClass MetaFeedbackActorClass;
struct _MetaFeedbackActorClass
{
/*< private >*/
ClutterActorClass parent_class;
};
struct _MetaFeedbackActor
{
ClutterActor parent;
};
GType meta_feedback_actor_get_type (void);
ClutterActor *meta_feedback_actor_new (int anchor_x,
int anchor_y);
void meta_feedback_actor_set_anchor (MetaFeedbackActor *actor,
int anchor_x,
int anchor_y);
void meta_feedback_actor_get_anchor (MetaFeedbackActor *actor,
int *anchor_x,
int *anchor_y);
void meta_feedback_actor_set_position (MetaFeedbackActor *self,
int x,
int y);
void meta_feedback_actor_update (MetaFeedbackActor *self,
const ClutterEvent *event);
#endif /* META_FEEDBACK_ACTOR_PRIVATE_H */

View File

@ -0,0 +1,249 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
/**
* SECTION:meta-feedback-actor
* @title: MetaFeedbackActor
* @short_description: Actor for painting user interaction feedback
*/
#include <config.h>
#include "display-private.h"
#include "compositor-private.h"
#include "meta-feedback-actor-private.h"
enum {
PROP_ANCHOR_X = 1,
PROP_ANCHOR_Y
};
typedef struct _MetaFeedbackActorPrivate MetaFeedbackActorPrivate;
struct _MetaFeedbackActorPrivate
{
int anchor_x;
int anchor_y;
int pos_x;
int pos_y;
};
G_DEFINE_TYPE_WITH_PRIVATE (MetaFeedbackActor, meta_feedback_actor, CLUTTER_TYPE_ACTOR)
static void
meta_feedback_actor_constructed (GObject *object)
{
MetaDisplay *display;
display = meta_get_display ();
clutter_actor_add_child (display->compositor->feedback_group,
CLUTTER_ACTOR (object));
}
static void
meta_feedback_actor_update_position (MetaFeedbackActor *self)
{
MetaFeedbackActorPrivate *priv = meta_feedback_actor_get_instance_private (self);
clutter_actor_set_position (CLUTTER_ACTOR (self),
priv->pos_x - priv->anchor_x,
priv->pos_y - priv->anchor_y);
}
static void
meta_feedback_actor_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaFeedbackActor *self = META_FEEDBACK_ACTOR (object);
MetaFeedbackActorPrivate *priv = meta_feedback_actor_get_instance_private (self);
switch (prop_id)
{
case PROP_ANCHOR_X:
priv->anchor_x = g_value_get_int (value);
meta_feedback_actor_update_position (self);
break;
case PROP_ANCHOR_Y:
priv->anchor_y = g_value_get_int (value);
meta_feedback_actor_update_position (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_feedback_actor_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaFeedbackActor *self = META_FEEDBACK_ACTOR (object);
MetaFeedbackActorPrivate *priv = meta_feedback_actor_get_instance_private (self);
switch (prop_id)
{
case PROP_ANCHOR_X:
g_value_set_int (value, priv->anchor_x);
break;
case PROP_ANCHOR_Y:
g_value_set_int (value, priv->anchor_y);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_feedback_actor_class_init (MetaFeedbackActorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
object_class->constructed = meta_feedback_actor_constructed;
object_class->set_property = meta_feedback_actor_set_property;
object_class->get_property = meta_feedback_actor_get_property;
pspec = g_param_spec_int ("anchor-x",
"Anchor X",
"The X axis of the anchor point",
0, G_MAXINT, 0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_ANCHOR_X,
pspec);
pspec = g_param_spec_int ("anchor-y",
"Anchor Y",
"The Y axis of the anchor point",
0, G_MAXINT, 0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_ANCHOR_Y,
pspec);
}
static void
meta_feedback_actor_init (MetaFeedbackActor *self)
{
clutter_actor_set_reactive (CLUTTER_ACTOR (self), FALSE);
}
/**
* meta_feedback_actor_new:
*
* Creates a new actor to draw the current drag and drop surface.
*
* Return value: the newly created background actor
*/
ClutterActor *
meta_feedback_actor_new (int anchor_x,
int anchor_y)
{
MetaFeedbackActor *self;
self = g_object_new (META_TYPE_FEEDBACK_ACTOR,
"anchor-x", anchor_x,
"anchor-y", anchor_y,
NULL);
return CLUTTER_ACTOR (self);
}
void
meta_feedback_actor_set_anchor (MetaFeedbackActor *self,
int anchor_x,
int anchor_y)
{
MetaFeedbackActorPrivate *priv;
g_return_if_fail (META_IS_FEEDBACK_ACTOR (self));
priv = meta_feedback_actor_get_instance_private (self);
if (priv->anchor_x == anchor_x && priv->anchor_y == anchor_y)
return;
if (priv->anchor_x != anchor_y)
{
priv->anchor_x = anchor_x;
g_object_notify (G_OBJECT (self), "anchor-x");
}
if (priv->anchor_y != anchor_y)
{
priv->anchor_y = anchor_y;
g_object_notify (G_OBJECT (self), "anchor-y");
}
meta_feedback_actor_update_position (self);
}
void
meta_feedback_actor_get_anchor (MetaFeedbackActor *self,
int *anchor_x,
int *anchor_y)
{
MetaFeedbackActorPrivate *priv;
g_return_if_fail (META_IS_FEEDBACK_ACTOR (self));
priv = meta_feedback_actor_get_instance_private (self);
if (anchor_x)
*anchor_x = priv->anchor_x;
if (anchor_y)
*anchor_y = priv->anchor_y;
}
void
meta_feedback_actor_set_position (MetaFeedbackActor *self,
int x,
int y)
{
MetaFeedbackActorPrivate *priv;
g_return_if_fail (META_IS_FEEDBACK_ACTOR (self));
priv = meta_feedback_actor_get_instance_private (self);
priv->pos_x = x;
priv->pos_y = y;
meta_feedback_actor_update_position (self);
}
void
meta_feedback_actor_update (MetaFeedbackActor *self,
const ClutterEvent *event)
{
ClutterPoint point;
g_return_if_fail (META_IS_FEEDBACK_ACTOR (self));
g_return_if_fail (event != NULL);
clutter_event_get_position (event, &point);
meta_feedback_actor_set_position (self, point.x, point.y);
}

View File

@ -343,7 +343,7 @@ meta_shaped_texture_paint (ClutterActor *actor)
filter = COGL_PIPELINE_FILTER_LINEAR;
if (!clutter_actor_is_in_clone_paint (actor) && meta_actor_is_untransformed (actor, NULL, NULL))
if (meta_actor_painting_untransformed (tex_width, tex_height, NULL, NULL))
filter = COGL_PIPELINE_FILTER_NEAREST;
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());

View File

@ -193,8 +193,8 @@ meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
MetaRectangle window_rect;
meta_window_get_frame_rect (priv->window, &window_rect);
if (window_rect.x == x &&
window_rect.y == y &&
if (x == 0 &&
y == 0 &&
window_rect.width == width &&
window_rect.height == height)
priv->full_damage_frames_count++;
@ -383,6 +383,7 @@ window_decorated_notify (MetaWindow *window,
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (user_data);
detach_pixmap (self);
free_damage (self);
create_damage (self);
}

View File

@ -100,7 +100,7 @@ struct _MetaWindowActorPrivate
guint disposed : 1;
/* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
* client message using the most recent frame in ->frames */
* client message for one or more messages in ->frames */
guint needs_frame_drawn : 1;
guint repaint_scheduled : 1;
@ -118,10 +118,21 @@ struct _MetaWindowActorPrivate
typedef struct _FrameData FrameData;
/* Each time the application updates the sync request counter to a new even value
* value, we queue a frame into the windows list of frames. Once we're painting
* an update "in response" to the window, we fill in frame_counter with the
* Cogl counter for that frame, and send _NET_WM_FRAME_DRAWN at the end of the
* frame. _NET_WM_FRAME_TIMINGS is sent when we get a frame_complete callback.
*
* As an exception, if a window is completely obscured, we try to throttle drawning
* to a slower frame rate. In this case, frame_counter stays -1 until
* send_frame_message_timeout() runs, at which point we send both the
* _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages.
*/
struct _FrameData
{
int64_t frame_counter;
guint64 sync_request_serial;
int64_t frame_counter;
gint64 frame_drawn_time;
};
@ -655,6 +666,30 @@ clip_shadow_under_window (MetaWindowActor *self)
return is_non_opaque (self) && priv->window->frame;
}
static void
assign_frame_counter_to_frames (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
GList *l;
/* If the window is obscured, then we're expecting to deal with sending
* frame messages in a timeout, rather than in this paint cycle.
*/
if (priv->send_frame_messages_timer != 0)
return;
for (l = priv->frames; l; l = l->next)
{
FrameData *frame = l->data;
if (frame->frame_counter == -1)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer());
frame->frame_counter = cogl_onscreen_get_frame_counter (onscreen);
}
}
}
static void
meta_window_actor_paint (ClutterActor *actor)
{
@ -671,6 +706,8 @@ meta_window_actor_paint (ClutterActor *actor)
{
g_source_remove (priv->send_frame_messages_timer);
priv->send_frame_messages_timer = 0;
assign_frame_counter_to_frames (self);
}
if (shadow != NULL)
@ -865,7 +902,7 @@ meta_window_actor_get_surface (MetaWindowActor *self)
gboolean
meta_window_actor_is_destroyed (MetaWindowActor *self)
{
return self->priv->disposed;
return self->priv->disposed || self->priv->needs_destroy;
}
static gboolean
@ -873,16 +910,27 @@ send_frame_messages_timeout (gpointer data)
{
MetaWindowActor *self = (MetaWindowActor *) data;
MetaWindowActorPrivate *priv = self->priv;
FrameData *frame = g_slice_new0 (FrameData);
GList *l;
frame->sync_request_serial = priv->window->sync_request_serial;
for (l = priv->frames; l;)
{
GList *l_next = l->next;
FrameData *frame = l->data;
do_send_frame_drawn (self, frame);
do_send_frame_timings (self, frame, 0, 0);
if (frame->frame_counter == -1)
{
do_send_frame_drawn (self, frame);
do_send_frame_timings (self, frame, 0, 0);
priv->frames = g_list_delete_link (priv->frames, l);
frame_data_free (frame);
}
l = l_next;
}
priv->needs_frame_drawn = FALSE;
priv->send_frame_messages_timer = 0;
frame_data_free (frame);
return FALSE;
}
@ -891,6 +939,10 @@ static void
queue_send_frame_messages_timeout (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->send_frame_messages_timer != 0)
return;
MetaDisplay *display = meta_window_get_display (priv->window);
gint64 current_time = meta_compositor_monotonic_time_to_server_time (display, g_get_monotonic_time ());
MetaMonitorManager *monitor_manager = meta_monitor_manager_get ();
@ -927,7 +979,13 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
gboolean no_delay_frame)
{
MetaWindowActorPrivate *priv = self->priv;
FrameData *frame = g_slice_new0 (FrameData);
FrameData *frame;
if (meta_window_actor_is_destroyed (self))
return;
frame = g_slice_new0 (FrameData);
frame->frame_counter = -1;
priv->needs_frame_drawn = TRUE;
@ -1150,7 +1208,7 @@ gboolean
meta_window_actor_should_unredirect (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->surface)
if (!meta_window_actor_is_destroyed (self) && priv->surface)
return meta_surface_actor_should_unredirect (priv->surface);
else
return FALSE;
@ -1171,7 +1229,6 @@ meta_window_actor_destroy (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
MetaWindow *window = priv->window;
MetaCompositor *compositor = priv->compositor;
MetaWindowType window_type = meta_window_get_window_type (window);
meta_window_set_compositor_private (window, NULL);
@ -1182,12 +1239,6 @@ meta_window_actor_destroy (MetaWindowActor *self)
priv->send_frame_messages_timer = 0;
}
/*
* We remove the window from internal lookup hashes and thus any other
* unmap events etc fail
*/
compositor->windows = g_list_remove (compositor->windows, (gconstpointer) self);
if (window_type == META_WINDOW_DROPDOWN_MENU ||
window_type == META_WINDOW_POPUP_MENU ||
window_type == META_WINDOW_TOOLTIP ||
@ -1907,21 +1958,12 @@ meta_window_actor_handle_updates (MetaWindowActor *self)
void
meta_window_actor_pre_paint (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
GList *l;
if (meta_window_actor_is_destroyed (self))
return;
meta_window_actor_handle_updates (self);
for (l = priv->frames; l != NULL; l = l->next)
{
FrameData *frame = l->data;
if (frame->frame_counter == 0)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer());
frame->frame_counter = cogl_onscreen_get_frame_counter (onscreen);
}
}
assign_frame_counter_to_frames (self);
}
static void
@ -1959,16 +2001,26 @@ 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)
if (meta_window_actor_is_destroyed (self))
return;
if (priv->needs_frame_drawn)
/* If the window had damage, but wasn't actually redrawn because
* it is obscured, we should wait until timer expiration before
* sending _NET_WM_FRAME_* messages.
*/
if (priv->send_frame_messages_timer == 0 &&
priv->needs_frame_drawn)
{
do_send_frame_drawn (self, priv->frames->data);
GList *l;
for (l = priv->frames; l; l = l->next)
{
FrameData *frame = l->data;
if (frame->frame_drawn_time == 0)
do_send_frame_drawn (self, frame);
}
priv->needs_frame_drawn = FALSE;
}
@ -2046,19 +2098,27 @@ meta_window_actor_frame_complete (MetaWindowActor *self,
MetaWindowActorPrivate *priv = self->priv;
GList *l;
if (meta_window_actor_is_destroyed (self))
return;
for (l = priv->frames; l;)
{
GList *l_next = l->next;
FrameData *frame = l->data;
gint64 frame_counter = cogl_frame_info_get_frame_counter (frame_info);
if (frame->frame_counter == cogl_frame_info_get_frame_counter (frame_info))
if (frame->frame_counter != -1 && frame->frame_counter <= frame_counter)
{
if (frame->frame_drawn_time != 0)
{
priv->frames = g_list_delete_link (priv->frames, l);
send_frame_timings (self, frame, frame_info, presentation_time);
frame_data_free (frame);
}
if (G_UNLIKELY (frame->frame_drawn_time == 0))
g_warning ("%s: Frame has assigned frame counter but no frame drawn time",
priv->window->desc);
if (G_UNLIKELY (frame->frame_counter < frame_counter))
g_warning ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT,
priv->window->desc, frame->frame_counter);
priv->frames = g_list_delete_link (priv->frames, l);
send_frame_timings (self, frame, frame_info, presentation_time);
frame_data_free (frame);
}
l = l_next;

View File

@ -31,64 +31,6 @@ static void cullable_iface_init (MetaCullableInterface *iface);
G_DEFINE_TYPE_WITH_CODE (MetaWindowGroup, meta_window_group, CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
/* Help macros to scale from OpenGL <-1,1> coordinates system to
* window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c
*/
#define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
/* Check if we're painting the MetaWindowGroup "untransformed". This can
* differ from the result of actor_is_untransformed(window_group) if we're
* inside a clone paint. The integer translation, if any, is returned.
*/
static gboolean
painting_untransformed (MetaWindowGroup *window_group,
int *x_origin,
int *y_origin)
{
CoglMatrix modelview, projection, modelview_projection;
ClutterVertex vertices[4];
int width, height;
float viewport[4];
int i;
cogl_get_modelview_matrix (&modelview);
cogl_get_projection_matrix (&projection);
cogl_matrix_multiply (&modelview_projection,
&projection,
&modelview);
meta_screen_get_size (window_group->screen, &width, &height);
vertices[0].x = 0;
vertices[0].y = 0;
vertices[0].z = 0;
vertices[1].x = width;
vertices[1].y = 0;
vertices[1].z = 0;
vertices[2].x = 0;
vertices[2].y = height;
vertices[2].z = 0;
vertices[3].x = width;
vertices[3].y = height;
vertices[3].z = 0;
cogl_get_viewport (viewport);
for (i = 0; i < 4; i++)
{
float w = 1;
cogl_matrix_transform_point (&modelview_projection, &vertices[i].x, &vertices[i].y, &vertices[i].z, &w);
vertices[i].x = MTX_GL_SCALE_X (vertices[i].x, w,
viewport[2], viewport[0]);
vertices[i].y = MTX_GL_SCALE_Y (vertices[i].y, w,
viewport[3], viewport[1]);
}
return meta_actor_vertices_are_untransformed (vertices, width, height, x_origin, y_origin);
}
static void
meta_window_group_cull_out (MetaCullable *cullable,
cairo_region_t *unobscured_region,
@ -119,10 +61,13 @@ meta_window_group_paint (ClutterActor *actor)
int paint_x_offset, paint_y_offset;
int paint_x_origin, paint_y_origin;
int actor_x_origin, actor_y_origin;
int screen_width, screen_height;
MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
ClutterActor *stage = clutter_actor_get_stage (actor);
meta_screen_get_size (window_group->screen, &screen_width, &screen_height);
/* 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
* case and we need to compensate. We look at the position of the window
@ -136,7 +81,7 @@ meta_window_group_paint (ClutterActor *actor)
* painting currently, and never worry about how actors are positioned
* on the stage.
*/
if (!painting_untransformed (window_group, &paint_x_origin, &paint_y_origin) ||
if (!meta_actor_painting_untransformed (screen_width, screen_height, &paint_x_origin, &paint_y_origin) ||
!meta_actor_is_untransformed (actor, &actor_x_origin, &actor_y_origin))
{
CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);

View File

@ -295,7 +295,7 @@ on_monitors_changed (MetaScreen *screen,
{
MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin);
int i, n;
GRand *rand = g_rand_new_with_seed (12345);
GRand *rand = g_rand_new_with_seed (123456);
clutter_actor_destroy_all_children (self->priv->background_group);
@ -303,15 +303,16 @@ on_monitors_changed (MetaScreen *screen,
for (i = 0; i < n; i++)
{
MetaRectangle rect;
ClutterActor *background;
ClutterActor *background_actor;
MetaBackground *background;
ClutterColor color;
meta_screen_get_monitor_geometry (screen, i, &rect);
background = meta_background_actor_new ();
background_actor = meta_background_actor_new (screen, i);
clutter_actor_set_position (background, rect.x, rect.y);
clutter_actor_set_size (background, rect.width, rect.height);
clutter_actor_set_position (background_actor, rect.x, rect.y);
clutter_actor_set_size (background_actor, rect.width, rect.height);
/* Don't use rand() here, mesa calls srand() internally when
parsing the driconf XML, but it's nice if the colors are
@ -322,9 +323,13 @@ on_monitors_changed (MetaScreen *screen,
g_rand_int_range (rand, 0, 255),
g_rand_int_range (rand, 0, 255),
255);
clutter_actor_set_background_color (background, &color);
clutter_actor_add_child (self->priv->background_group, background);
background = meta_background_new (screen);
meta_background_set_color (background, &color);
meta_background_actor_set_background (META_BACKGROUND_ACTOR (background_actor), background);
g_object_unref (background);
clutter_actor_add_child (self->priv->background_group, background_actor);
}
g_rand_free (rand);

View File

@ -612,9 +612,14 @@ update_onscreen_requirements (MetaWindow *window,
*/
if (window->frame && window->decorated)
{
MetaRectangle titlebar_rect;
MetaRectangle titlebar_rect, frame_rect;
meta_window_get_titlebar_rect (window, &titlebar_rect);
meta_window_get_frame_rect (window, &frame_rect);
/* translate into screen coordinates */
titlebar_rect.x = frame_rect.x;
titlebar_rect.y = frame_rect.y;
old = window->require_titlebar_visible;
window->require_titlebar_visible =

View File

@ -57,6 +57,7 @@ typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
typedef enum {
META_LIST_DEFAULT = 0, /* normal windows */
META_LIST_INCLUDE_OVERRIDE_REDIRECT = 1 << 0, /* normal and O-R */
META_LIST_SORTED = 1 << 1, /* sort list by mru */
} MetaListWindowsFlags;
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
@ -97,6 +98,10 @@ typedef enum {
META_EVENT_ROUTE_WINDOW_OP,
} MetaEventRoute;
typedef gboolean (*MetaAlarmFilter) (MetaDisplay *display,
XSyncAlarmNotifyEvent *event,
gpointer data);
struct _MetaDisplay
{
GObject parent_instance;
@ -162,6 +167,7 @@ struct _MetaDisplay
/*< private-ish >*/
MetaScreen *screen;
GHashTable *xids;
GHashTable *stamps;
GHashTable *wayland_windows;
/* serials of leave/unmap events that may
@ -256,6 +262,9 @@ struct _MetaDisplay
MetaGestureTracker *gesture_tracker;
ClutterEventSequence *pointer_emulating_sequence;
MetaAlarmFilter alarm_filter;
gpointer alarm_filter_data;
int composite_event_base;
int composite_error_base;
int composite_major_version;
@ -334,6 +343,29 @@ void meta_display_register_x_window (MetaDisplay *display,
void meta_display_unregister_x_window (MetaDisplay *display,
Window xwindow);
/* Each MetaWindow is uniquely identified by a 64-bit "stamp"; unlike a
* a MetaWindow *, a stamp will never be recycled
*/
MetaWindow* meta_display_lookup_stamp (MetaDisplay *display,
guint64 stamp);
void meta_display_register_stamp (MetaDisplay *display,
guint64 *stampp,
MetaWindow *window);
void meta_display_unregister_stamp (MetaDisplay *display,
guint64 stamp);
/* A "stack id" is a XID or a stamp */
#define META_STACK_ID_IS_X11(id) ((id) < G_GUINT64_CONSTANT(0x100000000))
MetaWindow* meta_display_lookup_stack_id (MetaDisplay *display,
guint64 stack_id);
/* for debug logging only; returns a human-description of the stack
* ID - a small number of buffers are recycled, so the result must
* be used immediately or copied */
const char *meta_display_describe_stack_id (MetaDisplay *display,
guint64 stack_id);
void meta_display_register_wayland_window (MetaDisplay *display,
MetaWindow *window);
void meta_display_unregister_wayland_window (MetaDisplay *display,
@ -453,4 +485,8 @@ void meta_display_cancel_touch (MetaDisplay *display);
gboolean meta_display_windows_are_interactable (MetaDisplay *display);
void meta_display_set_alarm_filter (MetaDisplay *display,
MetaAlarmFilter filter,
gpointer data);
#endif

View File

@ -150,6 +150,9 @@ static void update_cursor_theme (void);
static void prefs_changed_callback (MetaPreference pref,
void *data);
static int mru_cmp (gconstpointer a,
gconstpointer b);
static void
meta_display_get_property(GObject *object,
guint prop_id,
@ -627,6 +630,8 @@ meta_display_open (void)
display->xids = g_hash_table_new (meta_unsigned_long_hash,
meta_unsigned_long_equal);
display->stamps = g_hash_table_new (g_int64_hash,
g_int64_equal);
display->wayland_windows = g_hash_table_new (NULL, NULL);
i = 0;
@ -1002,7 +1007,7 @@ meta_display_list_windows (MetaDisplay *display,
{
MetaWindow *window = value;
if (!META_IS_WINDOW (window))
if (!META_IS_WINDOW (window) || window->unmanaging)
continue;
if (!window->override_redirect ||
@ -1015,7 +1020,7 @@ meta_display_list_windows (MetaDisplay *display,
{
MetaWindow *window = value;
if (!META_IS_WINDOW (window))
if (!META_IS_WINDOW (window) || window->unmanaging)
continue;
if (!window->override_redirect ||
@ -1059,6 +1064,9 @@ meta_display_list_windows (MetaDisplay *display,
tmp = next;
}
if (flags & META_LIST_SORTED)
winlist = g_slist_sort (winlist, mru_cmp);
return winlist;
}
@ -1581,6 +1589,68 @@ meta_display_unregister_wayland_window (MetaDisplay *display,
g_hash_table_remove (display->wayland_windows, window);
}
MetaWindow*
meta_display_lookup_stamp (MetaDisplay *display,
guint64 stamp)
{
return g_hash_table_lookup (display->stamps, &stamp);
}
void
meta_display_register_stamp (MetaDisplay *display,
guint64 *stampp,
MetaWindow *window)
{
g_return_if_fail (g_hash_table_lookup (display->stamps, stampp) == NULL);
g_hash_table_insert (display->stamps, stampp, window);
}
void
meta_display_unregister_stamp (MetaDisplay *display,
guint64 stamp)
{
g_return_if_fail (g_hash_table_lookup (display->stamps, &stamp) != NULL);
g_hash_table_remove (display->stamps, &stamp);
}
MetaWindow*
meta_display_lookup_stack_id (MetaDisplay *display,
guint64 stack_id)
{
if (META_STACK_ID_IS_X11 (stack_id))
return meta_display_lookup_x_window (display, (Window)stack_id);
else
return meta_display_lookup_stamp (display, stack_id);
}
/* We return a pointer into a ring of static buffers. This is to make
* using this function for debug-logging convenient and avoid tempory
* strings that must be freed. */
const char *
meta_display_describe_stack_id (MetaDisplay *display,
guint64 stack_id)
{
/* 0x<64-bit: 16 characters> (<10 characters of title>)\0' */
static char buffer[5][32];
MetaWindow *window;
static int pos = 0;
char *result;
result = buffer[pos];
pos = (pos + 1) % 5;
window = meta_display_lookup_stack_id (display, stack_id);
if (window && window->title)
snprintf (result, sizeof(buffer[0]), "%#" G_GINT64_MODIFIER "x (%.10s)", stack_id, window->title);
else
snprintf (result, sizeof(buffer[0]), "%#" G_GINT64_MODIFIER "x", stack_id);
return result;
}
/* 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
* typesafe functions to register/unregister for readability.
@ -1895,7 +1965,7 @@ meta_display_end_grab_op (MetaDisplay *display,
* beginning of the grab_op.
*/
if (!meta_prefs_get_raise_on_click () &&
display->grab_threshold_movement_reached)
!display->grab_threshold_movement_reached)
meta_window_raise (display->grab_window);
meta_window_grab_op_ended (grab_window, grab_op);
@ -2370,13 +2440,22 @@ meta_display_get_tab_list (MetaDisplay *display,
mru_list = workspace ? workspace->mru_list : global_mru_list;
/* Windows sellout mode - MRU order.
/* Windows sellout mode - MRU order. Collect unminimized windows
* then minimized so minimized windows aren't in the way so much.
*/
for (tmp = mru_list; tmp; tmp = tmp->next)
{
MetaWindow *window = tmp->data;
if (IN_TAB_CHAIN (window, type))
if (!window->minimized && IN_TAB_CHAIN (window, type))
tab_list = g_list_prepend (tab_list, window);
}
for (tmp = mru_list; tmp; tmp = tmp->next)
{
MetaWindow *window = tmp->data;
if (window->minimized && IN_TAB_CHAIN (window, type))
tab_list = g_list_prepend (tab_list, window);
}
@ -2954,3 +3033,14 @@ meta_display_is_pointer_emulating_sequence (MetaDisplay *display,
return display->pointer_emulating_sequence == sequence;
}
void
meta_display_set_alarm_filter (MetaDisplay *display,
MetaAlarmFilter filter,
gpointer data)
{
g_return_if_fail (filter == NULL || display->alarm_filter == NULL);
display->alarm_filter = filter;
display->alarm_filter_data = data;
}

View File

@ -28,6 +28,7 @@
#include "display-private.h"
#include "window-private.h"
#include "backends/x11/meta-backend-x11.h"
#include "backends/meta-cursor-tracker-private.h"
#ifdef HAVE_NATIVE_BACKEND
#include "backends/native/meta-backend-native.h"
@ -35,7 +36,6 @@
#endif
#ifdef HAVE_WAYLAND
#include "backends/meta-cursor-tracker-private.h"
#include "wayland/meta-wayland-private.h"
#endif
#include "meta-surface-actor.h"
@ -188,13 +188,11 @@ meta_display_handle_event (MetaDisplay *display,
}
#endif
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor () && event->type == CLUTTER_MOTION)
{
MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (NULL);
meta_cursor_tracker_update_position (tracker, event->motion.x, event->motion.y);
}
#endif
handle_idletime_for_event (event);

View File

@ -39,7 +39,6 @@ meta_window_ensure_frame (MetaWindow *window)
XSetWindowAttributes attrs;
Visual *visual;
gulong create_serial;
MetaStackWindow stack_window;
if (window->frame)
return;
@ -95,10 +94,8 @@ meta_window_ensure_frame (MetaWindow *window)
frame->rect.height,
frame->window->screen->number,
&create_serial);
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
stack_window.x11.xwindow = frame->xwindow;
meta_stack_tracker_record_add (window->screen->stack_tracker,
&stack_window,
frame->xwindow,
create_serial);
meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow);
@ -132,9 +129,8 @@ meta_window_ensure_frame (MetaWindow *window)
window->unmaps_pending += 1;
}
stack_window.x11.xwindow = window->xwindow;
meta_stack_tracker_record_remove (window->screen->stack_tracker,
&stack_window,
window->xwindow,
XNextRequest (window->display->xdisplay));
XReparentWindow (window->display->xdisplay,
window->xwindow,
@ -179,7 +175,6 @@ meta_window_destroy_frame (MetaWindow *window)
{
MetaFrame *frame;
MetaFrameBorders borders;
MetaStackWindow stack_window;
if (window->frame == NULL)
return;
@ -206,10 +201,8 @@ meta_window_destroy_frame (MetaWindow *window)
"Incrementing unmaps_pending on %s for reparent back to root\n", window->desc);
window->unmaps_pending += 1;
}
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
stack_window.x11.xwindow = window->xwindow;
meta_stack_tracker_record_add (window->screen->stack_tracker,
&stack_window,
window->xwindow,
XNextRequest (window->display->xdisplay));
XReparentWindow (window->display->xdisplay,
window->xwindow,

View File

@ -101,6 +101,8 @@ typedef struct
MetaKeyCombo *iso_next_group_combos;
int n_iso_next_group_combos;
xkb_level_index_t keymap_num_levels;
/* Alt+click button grabs */
ClutterModifierType window_grab_modifiers;
} MetaKeyBindingManager;

View File

@ -40,7 +40,11 @@
#include <meta/prefs.h>
#include "meta-accel-parse.h"
#ifdef __linux__
#include <linux/input.h>
#elif !defined KEY_GRAVE
#define KEY_GRAVE 0x29 /* assume the use of xf86-input-keyboard */
#endif
#include "backends/x11/meta-backend-x11.h"
#include "x11/window-x11.h"
@ -236,29 +240,19 @@ reload_modmap (MetaKeyBindingManager *keys)
static gboolean
is_keycode_for_keysym (struct xkb_keymap *keymap,
xkb_layout_index_t layout,
xkb_level_index_t level,
xkb_keycode_t keycode,
xkb_keysym_t keysym)
{
xkb_layout_index_t num_layouts, i;
const xkb_keysym_t *syms;
int num_syms, k;
num_layouts = xkb_keymap_num_layouts_for_key (keymap, keycode);
for (i = 0; i < num_layouts; i++)
num_syms = xkb_keymap_key_get_syms_by_level (keymap, keycode, layout, level, &syms);
for (k = 0; k < num_syms; k++)
{
xkb_level_index_t num_levels, j;
num_levels = xkb_keymap_num_levels_for_key (keymap, keycode, i);
for (j = 0; j < num_levels; j++)
{
const xkb_keysym_t *syms;
int num_syms, k;
num_syms = xkb_keymap_key_get_syms_by_level (keymap, keycode, i, j, &syms);
for (k = 0; k < num_syms; k++)
{
if (syms[k] == keysym)
return TRUE;
}
}
if (syms[k] == keysym)
return TRUE;
}
return FALSE;
@ -268,6 +262,8 @@ typedef struct
{
GArray *keycodes;
xkb_keysym_t keysym;
xkb_layout_index_t layout;
xkb_level_index_t level;
} FindKeysymData;
static void
@ -278,8 +274,10 @@ get_keycodes_for_keysym_iter (struct xkb_keymap *keymap,
FindKeysymData *search_data = data;
GArray *keycodes = search_data->keycodes;
xkb_keysym_t keysym = search_data->keysym;
xkb_layout_index_t layout = search_data->layout;
xkb_level_index_t level = search_data->level;
if (is_keycode_for_keysym (keymap, keycode, keysym))
if (is_keycode_for_keysym (keymap, layout, level, keycode, keysym))
g_array_append_val (keycodes, keycode);
}
@ -307,8 +305,15 @@ get_keycodes_for_keysym (MetaKeyBindingManager *keys,
{
MetaBackend *backend = meta_get_backend ();
struct xkb_keymap *keymap = meta_backend_get_keymap (backend);
FindKeysymData search_data = { retval, keysym };
xkb_keymap_key_for_each (keymap, get_keycodes_for_keysym_iter, &search_data);
xkb_layout_index_t i;
xkb_level_index_t j;
for (i = 0; i < xkb_keymap_num_layouts (keymap); i++)
for (j = 0; j < keys->keymap_num_levels; j++)
{
FindKeysymData search_data = { retval, keysym, i, j };
xkb_keymap_key_for_each (keymap, get_keycodes_for_keysym_iter, &search_data);
}
}
out:
@ -319,7 +324,7 @@ get_keycodes_for_keysym (MetaKeyBindingManager *keys,
static guint
get_first_keycode_for_keysym (MetaKeyBindingManager *keys,
guint keysym)
guint keysym)
{
int *keycodes;
int n_keycodes;
@ -336,6 +341,32 @@ get_first_keycode_for_keysym (MetaKeyBindingManager *keys,
return keycode;
}
static void
determine_keymap_num_levels_iter (struct xkb_keymap *keymap,
xkb_keycode_t keycode,
void *data)
{
xkb_level_index_t *num_levels = data;
xkb_layout_index_t i;
for (i = 0; i < xkb_keymap_num_layouts_for_key (keymap, keycode); i++)
{
xkb_level_index_t level = xkb_keymap_num_levels_for_key (keymap, keycode, i);
if (level > *num_levels)
*num_levels = level;
}
}
static void
determine_keymap_num_levels (MetaKeyBindingManager *keys)
{
MetaBackend *backend = meta_get_backend ();
struct xkb_keymap *keymap = meta_backend_get_keymap (backend);
keys->keymap_num_levels = 0;
xkb_keymap_key_for_each (keymap, determine_keymap_num_levels_iter, &keys->keymap_num_levels);
}
static void
reload_iso_next_group_combos (MetaKeyBindingManager *keys)
{
@ -484,6 +515,8 @@ reload_keycodes (MetaKeyBindingManager *keys)
meta_topic (META_DEBUG_KEYBINDINGS,
"Reloading keycodes for binding tables\n");
determine_keymap_num_levels (keys);
if (keys->overlay_key_combo.keysym != 0)
{
keys->overlay_key_combo.keycode =
@ -1629,12 +1662,22 @@ meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp)
void
meta_display_freeze_keyboard (MetaDisplay *display, Window window, guint32 timestamp)
{
MetaBackend *backend = meta_get_backend ();
if (!META_IS_BACKEND_X11 (backend))
return;
grab_keyboard (window, timestamp, XIGrabModeSync);
}
void
meta_display_ungrab_keyboard (MetaDisplay *display, guint32 timestamp)
{
MetaBackend *backend = meta_get_backend ();
if (!META_IS_BACKEND_X11 (backend))
return;
ungrab_keyboard (timestamp);
}
@ -1877,6 +1920,8 @@ process_iso_next_group (MetaDisplay *display,
{
MetaKeyBindingManager *keys = &display->key_binding_manager;
gboolean activate;
guint32 keycode;
guint32 modifiers;
int i;
if (event->type == CLUTTER_KEY_RELEASE)
@ -1884,10 +1929,13 @@ process_iso_next_group (MetaDisplay *display,
activate = FALSE;
keycode = event->hardware_keycode;
modifiers = event->modifier_state & 0xff & ~keys->ignored_modifier_mask;
for (i = 0; i < keys->n_iso_next_group_combos; ++i)
{
if (event->hardware_keycode == keys->iso_next_group_combos[i].keycode &&
event->modifier_state == (unsigned int)keys->iso_next_group_combos[i].modifiers)
if (keycode == keys->iso_next_group_combos[i].keycode &&
modifiers == keys->iso_next_group_combos[i].modifiers)
{
/* If the signal handler returns TRUE the keyboard will
remain frozen. It's the signal handler's responsibility
@ -2907,10 +2955,6 @@ do_choose_window (MetaDisplay *display,
meta_topic (META_DEBUG_KEYBINDINGS,
"Tab list = %u\n", type);
/* reverse direction if shift is down */
if (event->modifier_state & CLUTTER_SHIFT_MASK)
backward = !backward;
window = meta_display_get_tab_next (display,
type,
screen->active_workspace,

View File

@ -302,7 +302,6 @@ meta_init (void)
{
struct sigaction act;
sigset_t empty_mask;
ClutterSettings *clutter_settings;
sigemptyset (&empty_mask);
act.sa_handler = SIG_IGN;
@ -377,13 +376,6 @@ meta_init (void)
meta_ui_init ();
meta_restart_init ();
/*
* XXX: We cannot handle high dpi scaling yet, so fix the scale to 1
* for now.
*/
clutter_settings = clutter_settings_get_default ();
g_object_set (clutter_settings, "window-scaling-factor", 1, NULL);
}
/**

View File

@ -52,9 +52,7 @@
#define KEY_GNOME_ACCESSIBILITY "toolkit-accessibility"
#define KEY_GNOME_ANIMATIONS "enable-animations"
#define KEY_GNOME_CURSOR_THEME "cursor-theme"
#define KEY_GNOME_CURSOR_SIZE "cursor-size"
#define KEY_XKB_OPTIONS "xkb-options"
#define KEY_XSETTINGS_OVERRIDES "overrides"
#define KEY_OVERLAY_KEY "overlay-key"
#define KEY_WORKSPACES_ONLY_ON_PRIMARY "workspaces-only-on-primary"
@ -133,9 +131,13 @@ static void bindings_changed (GSettings *settings,
gchar *key,
gpointer data);
static void xsettings_overrides_changed (GSettings *settings,
gchar *key,
gpointer data);
static void shell_shows_app_menu_changed (GtkSettings *settings,
GParamSpec *pspec,
gpointer data);
static void update_cursor_size (GtkSettings *settings,
GParamSpec *pspec,
gpointer data);
static void queue_changed (MetaPreference pref);
@ -479,13 +481,6 @@ static MetaIntPreference preferences_int[] =
},
&auto_raise_delay
},
{
{ "cursor-size",
SCHEMA_INTERFACE,
META_PREF_CURSOR_SIZE,
},
&cursor_size
},
{
{ "draggable-border-width",
SCHEMA_MUTTER,
@ -951,24 +946,6 @@ queue_changed (MetaPreference pref)
/* Initialisation. */
/****************************************************************************/
static GSettings *
get_xsettings_settings (void)
{
GSettings *settings = NULL;
GSettingsSchema *schema;
schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
SCHEMA_XSETTINGS, FALSE);
if (schema)
{
settings = g_settings_new_full (schema, NULL, NULL);
g_settings_schema_unref (schema);
}
return settings;
}
void
meta_prefs_init (void)
{
@ -998,19 +975,14 @@ meta_prefs_init (void)
G_CALLBACK (settings_changed), NULL);
g_signal_connect (settings, "changed::" KEY_GNOME_CURSOR_THEME,
G_CALLBACK (settings_changed), NULL);
g_signal_connect (settings, "changed::" KEY_GNOME_CURSOR_SIZE,
G_CALLBACK (settings_changed), NULL);
g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_INTERFACE), settings);
settings = get_xsettings_settings ();
if (settings)
{
g_signal_connect (settings, "changed::" KEY_XSETTINGS_OVERRIDES,
G_CALLBACK (xsettings_overrides_changed), NULL);
g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_XSETTINGS), settings);
g_signal_connect (gtk_settings_get_default (),
"notify::gtk-shell-shows-app-menu",
G_CALLBACK (shell_shows_app_menu_changed), NULL);
xsettings_overrides_changed (settings, KEY_XSETTINGS_OVERRIDES, NULL);
}
g_signal_connect (gtk_settings_get_default (), "notify::gtk-cursor-theme-size",
G_CALLBACK (update_cursor_size), NULL);
settings = g_settings_new (SCHEMA_INPUT_SOURCES);
g_signal_connect (settings, "changed::" KEY_XKB_OPTIONS,
@ -1032,6 +1004,9 @@ meta_prefs_init (void)
handle_preference_init_string_array ();
handle_preference_init_int ();
update_cursor_size (gtk_settings_get_default (), NULL, NULL);
shell_shows_app_menu_changed (gtk_settings_get_default (), NULL, NULL);
init_bindings ();
}
@ -1212,7 +1187,6 @@ settings_changed (GSettings *settings,
{
/* Unknown preference type. This quite likely simply isn't
* a preference we track changes to. */
return;
}
g_variant_unref (value);
@ -1232,44 +1206,49 @@ bindings_changed (GSettings *settings,
g_strfreev (strokes);
}
/* The fallback app menu should be enabled if either we are not
* showing the app menu (e.g. when using the default plugin) or
* with a corresponding XSettings override; we ignore the former
* and assume that we always show the app menu, not least
* because we rely on the compositor implementation to display
* the fallback ...
*/
static void
xsettings_overrides_changed (GSettings *settings,
gchar *key,
gpointer data)
shell_shows_app_menu_changed (GtkSettings *settings,
GParamSpec *pspec,
gpointer data)
{
GVariant *value;
GVariantDict overrides;
int shell_shows_app_menu = 1;
gboolean changed = FALSE;
if (!g_settings_get_boolean (settings, "active"))
goto out;
g_object_get (settings,
"gtk-shell-shows-app-menu", &shell_shows_app_menu,
NULL);
value = g_settings_get_value (settings, KEY_XSETTINGS_OVERRIDES);
g_variant_dict_init (&overrides, value);
g_variant_unref (value);
g_variant_dict_lookup (&overrides,
"Gtk/ShellShowsAppMenu", "i", &shell_shows_app_menu);
g_variant_dict_clear (&overrides);
changed = (show_fallback_app_menu == !!shell_shows_app_menu);
out:
show_fallback_app_menu = !shell_shows_app_menu;
if (changed)
queue_changed (META_PREF_BUTTON_LAYOUT);
}
static void
update_cursor_size (GtkSettings *settings,
GParamSpec *pspec,
gpointer data)
{
GdkScreen *screen = gdk_screen_get_default ();
GValue value = G_VALUE_INIT;
int xsettings_cursor_size = 24;
g_value_init (&value, G_TYPE_INT);
if (gdk_screen_get_setting (screen, "gtk-cursor-theme-size", &value))
{
xsettings_cursor_size = g_value_get_int (&value);
}
if (xsettings_cursor_size != cursor_size)
{
cursor_size = xsettings_cursor_size;
queue_changed (META_PREF_CURSOR_SIZE);
}
}
/**
* maybe_give_disable_workaround_warning:
*
@ -1347,26 +1326,10 @@ meta_prefs_get_cursor_theme (void)
return cursor_theme;
}
static int
get_scale_factor (void)
{
GdkScreen *screen;
GValue value = G_VALUE_INIT;
g_value_init (&value, G_TYPE_INT);
/* XXX: Should this be in ui/ ? Or MetaMonitorManager? */
screen = gdk_screen_get_default ();
if (gdk_screen_get_setting (screen, "gdk-window-scaling-factor", &value))
return g_value_get_int (&value);
else
return 1;
}
int
meta_prefs_get_cursor_size (void)
{
return cursor_size * get_scale_factor ();
return cursor_size;
}

View File

@ -441,7 +441,6 @@ create_guard_window (Display *xdisplay, MetaScreen *screen)
XSetWindowAttributes attributes;
Window guard_window;
gulong create_serial;
MetaStackWindow stack_window;
attributes.event_mask = NoEventMask;
attributes.override_redirect = True;
@ -487,29 +486,16 @@ create_guard_window (Display *xdisplay, MetaScreen *screen)
}
}
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
stack_window.x11.xwindow = guard_window;
meta_stack_tracker_record_add (screen->stack_tracker,
&stack_window,
guard_window,
create_serial);
meta_stack_tracker_record_lower (screen->stack_tracker,
&stack_window,
XNextRequest (xdisplay));
XLowerWindow (xdisplay, guard_window);
meta_stack_tracker_lower (screen->stack_tracker,
guard_window);
XMapWindow (xdisplay, guard_window);
return guard_window;
}
/* Set a black background on the root window so that we don't
* see confusing old copies of old windows when debugging
* and testing. */
static void
meta_screen_set_background (MetaScreen *screen)
{
XSetWindowBackground (screen->display->xdisplay, screen->xroot, 0x00000000);
}
MetaScreen*
meta_screen_new (MetaDisplay *display,
int number,
@ -714,7 +700,6 @@ meta_screen_new (MetaDisplay *display,
reload_monitor_infos (screen);
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
meta_screen_set_background (screen);
/* Handle creating a no_focus_window for this screen */
screen->no_focus_window =
@ -884,19 +869,20 @@ meta_screen_create_guard_window (MetaScreen *screen)
void
meta_screen_manage_all_windows (MetaScreen *screen)
{
MetaStackWindow *_children;
MetaStackWindow *children;
guint64 *_children;
guint64 *children;
int n_children, i;
meta_stack_freeze (screen->stack);
meta_stack_tracker_get_stack (screen->stack_tracker, &_children, &n_children);
/* Copy the stack as it will be modified as part of the loop */
children = g_memdup (_children, sizeof (MetaStackWindow) * n_children);
children = g_memdup (_children, sizeof (guint64) * n_children);
for (i = 0; i < n_children; ++i)
{
meta_window_x11_new (screen->display, children[i].x11.xwindow, TRUE,
g_assert (META_STACK_ID_IS_X11 (children[i]));
meta_window_x11_new (screen->display, children[i], TRUE,
META_COMP_EFFECT_NONE);
}
@ -3025,38 +3011,32 @@ static gboolean
check_fullscreen_func (gpointer data)
{
MetaScreen *screen = data;
GSList *windows;
GSList *tmp;
MetaWindow *window;
GSList *fullscreen_monitors = NULL;
GSList *obscured_monitors = NULL;
gboolean in_fullscreen_changed = FALSE;
int i;
screen->check_fullscreen_later = 0;
windows = meta_display_list_windows (screen->display,
META_LIST_INCLUDE_OVERRIDE_REDIRECT);
for (tmp = windows; tmp != NULL; tmp = tmp->next)
/* We consider a monitor in fullscreen if it contains a fullscreen window;
* however we make an exception for maximized windows above the fullscreen
* one, as in that case window+chrome fully obscure the fullscreen window.
*/
for (window = meta_stack_get_top (screen->stack);
window;
window = meta_stack_get_below (screen->stack, window, FALSE))
{
MetaWindow *window = tmp->data;
gboolean covers_monitors = FALSE;
if (window->screen != screen || window->hidden)
continue;
if (window->fullscreen)
/* The checks for determining a fullscreen window's layer are quite
* elaborate, and we do a poor job at keeping it dynamically up-to-date.
* (It depends, for example, on whether the focus window is on the
* same monitor as the fullscreen window.) But because we minimize
* fullscreen windows not in LAYER_FULLSCREEN (see below), if the
* layer is stale here, it's really bad, so just force recomputation for
* here. This is expensive, but hopefully this function won't be
* called too often.
*/
meta_window_update_layer (window);
if (window->override_redirect)
{
covers_monitors = TRUE;
}
else if (window->override_redirect)
{
/* We want to handle the case where an application is creating an
* override-redirect window the size of the screen (monitor) and treat
@ -3066,10 +3046,14 @@ check_fullscreen_func (gpointer data)
if (meta_window_is_monitor_sized (window))
covers_monitors = TRUE;
}
else
else if (window->maximized_horizontally &&
window->maximized_vertically)
{
if (window->layer == META_LAYER_FULLSCREEN)
covers_monitors = TRUE;
int monitor_index = meta_window_get_monitor (window);
/* + 1 to avoid NULL */
gpointer monitor_p = GINT_TO_POINTER(monitor_index + 1);
if (!g_slist_find (obscured_monitors, monitor_p))
obscured_monitors = g_slist_prepend (obscured_monitors, monitor_p);
}
if (covers_monitors)
@ -3083,30 +3067,16 @@ check_fullscreen_func (gpointer data)
{
/* + 1 to avoid NULL */
gpointer monitor_p = GINT_TO_POINTER(monitors[j] + 1);
if (!g_slist_find (fullscreen_monitors, monitor_p))
if (!g_slist_find (fullscreen_monitors, monitor_p) &&
!g_slist_find (obscured_monitors, monitor_p))
fullscreen_monitors = g_slist_prepend (fullscreen_monitors, monitor_p);
}
g_free (monitors);
}
/* If we find a window that is fullscreen but not in the FULLSCREEN
* layer, it means that we've kicked it out of the layer because
* we've focused another window on the same monitor. In this case
* it would be confusing to keep the window fullscreen and visible,
* so minimize it. We can't do the same thing for override-redirect
* windows, so we just hope the application does the right thing.
*/
if (!covers_monitors && window->fullscreen)
{
meta_window_minimize (window);
meta_topic (META_DEBUG_WINDOW_OPS,
"Minimizing %s: was fullscreen but in a lower layer\n",
window->desc);
}
}
g_slist_free (windows);
g_slist_free (obscured_monitors);
for (i = 0; i < screen->n_monitor_infos; i++)
{

File diff suppressed because it is too large Load Diff

View File

@ -39,51 +39,30 @@
typedef struct _MetaStackTracker MetaStackTracker;
typedef union _MetaStackWindow
{
struct {
MetaWindowClientType type;
} any;
struct {
MetaWindowClientType type;
Window xwindow;
} x11;
struct {
MetaWindowClientType type;
MetaWindow *meta_window;
} wayland;
} MetaStackWindow;
gboolean meta_stack_window_equal (const MetaStackWindow *a,
const MetaStackWindow *b);
MetaStackTracker *meta_stack_tracker_new (MetaScreen *screen);
void meta_stack_tracker_free (MetaStackTracker *tracker);
/* These functions are called when we make an X call that changes the
* stacking order; this allows MetaStackTracker to predict stacking
* order before it receives events back from the X server */
void meta_stack_tracker_record_add (MetaStackTracker *tracker,
const MetaStackWindow *window,
gulong serial);
void meta_stack_tracker_record_remove (MetaStackTracker *tracker,
const MetaStackWindow *window,
gulong serial);
void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker,
const MetaStackWindow *windows,
int n_windows,
gulong serial);
void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker,
const MetaStackWindow *window,
const MetaStackWindow *sibling,
gulong serial);
void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker,
const MetaStackWindow *window,
const MetaStackWindow *sibling,
gulong serial);
void meta_stack_tracker_record_lower (MetaStackTracker *tracker,
const MetaStackWindow *window,
gulong serial);
void meta_stack_tracker_record_add (MetaStackTracker *tracker,
guint64 window,
gulong serial);
void meta_stack_tracker_record_remove (MetaStackTracker *tracker,
guint64 window,
gulong serial);
/* We also have functions that also go ahead and do the work
*/
void meta_stack_tracker_lower (MetaStackTracker *tracker,
guint64 window);
void meta_stack_tracker_restack_managed (MetaStackTracker *tracker,
const guint64 *windows,
int n_windows);
void meta_stack_tracker_restack_at_bottom (MetaStackTracker *tracker,
const guint64 *new_order,
int n_new_order);
/* These functions are used to update the stack when we get events
* reflecting changes to the stacking order */
@ -96,9 +75,9 @@ void meta_stack_tracker_reparent_event (MetaStackTracker *tracker,
void meta_stack_tracker_configure_event (MetaStackTracker *tracker,
XConfigureEvent *event);
void meta_stack_tracker_get_stack (MetaStackTracker *tracker,
MetaStackWindow **windows,
int *n_entries);
void meta_stack_tracker_get_stack (MetaStackTracker *tracker,
guint64 **windows,
int *n_entries);
void meta_stack_tracker_sync_stack (MetaStackTracker *tracker);
void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker);

View File

@ -76,8 +76,6 @@ meta_stack_new (MetaScreen *screen)
stack->removed = NULL;
stack->freeze_count = 0;
stack->last_all_root_children_stacked = NULL;
stack->n_positions = 0;
stack->need_resort = FALSE;
@ -87,13 +85,6 @@ meta_stack_new (MetaScreen *screen)
return stack;
}
static void
free_last_all_root_children_stacked_cache (MetaStack *stack)
{
g_array_free (stack->last_all_root_children_stacked, TRUE);
stack->last_all_root_children_stacked = NULL;
}
void
meta_stack_free (MetaStack *stack)
{
@ -103,9 +94,6 @@ meta_stack_free (MetaStack *stack)
g_list_free (stack->added);
g_list_free (stack->removed);
if (stack->last_all_root_children_stacked)
free_last_all_root_children_stacked_cache (stack);
g_free (stack);
}
@ -113,6 +101,8 @@ void
meta_stack_add (MetaStack *stack,
MetaWindow *window)
{
g_return_if_fail (!window->override_redirect);
meta_topic (META_DEBUG_STACK, "Adding window %s to the stack\n", window->desc);
if (window->stack_position >= 0)
@ -1030,194 +1020,6 @@ stack_ensure_sorted (MetaStack *stack)
stack_do_resort (stack);
}
static MetaStackWindow *
find_top_most_managed_window (MetaScreen *screen,
const MetaStackWindow *ignore)
{
MetaStackTracker *stack_tracker = screen->stack_tracker;
MetaStackWindow *windows;
int n_windows;
int i;
meta_stack_tracker_get_stack (stack_tracker,
&windows, &n_windows);
/* Children are in order from bottom to top. We want to
* find the topmost managed child, then configure
* our window to be above it.
*/
for (i = n_windows -1; i >= 0; i--)
{
MetaStackWindow *other_window = &windows[i];
if (other_window->any.type == ignore->any.type &&
((other_window->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
other_window->x11.xwindow == ignore->x11.xwindow) ||
other_window->wayland.meta_window == ignore->wayland.meta_window))
{
/* Do nothing. This means we're already the topmost managed
* window, but it DOES NOT mean we are already just above
* the topmost managed window. This is important because if
* an override redirect window is up, and we map a new
* managed window, the new window is probably above the old
* popup by default, and we want to push it below that
* popup. So keep looking for a sibling managed window
* to be moved below.
*/
}
else
{
if (other_window->any.type == META_WINDOW_CLIENT_TYPE_X11)
{
MetaWindow *other = meta_display_lookup_x_window (screen->display,
other_window->x11.xwindow);
if (other != NULL && !other->override_redirect)
return other_window;
}
else
{
/* All wayland windows are currently considered "managed"
* TODO: consider wayland pop-up windows like override
* redirect windows here. */
return other_window;
}
}
}
return NULL;
}
/* When moving an X window we sometimes need an X based sibling.
*
* If the given sibling is X based this function returns it back
* otherwise it searches downwards looking for the nearest X window.
*
* If no X based sibling could be found return NULL. */
static MetaStackWindow *
find_x11_sibling_downwards (MetaScreen *screen,
MetaStackWindow *sibling)
{
MetaStackTracker *stack_tracker = screen->stack_tracker;
MetaStackWindow *windows;
int n_windows;
int i;
if (sibling->any.type == META_WINDOW_CLIENT_TYPE_X11)
return sibling;
meta_stack_tracker_get_stack (stack_tracker,
&windows, &n_windows);
/* NB: Children are in order from bottom to top and we
* want to search downwards for the nearest X window.
*/
for (i = n_windows - 1; i >= 0; i--)
if (meta_stack_window_equal (&windows[i], sibling))
break;
for (; i >= 0; i--)
{
if (windows[i].any.type == META_WINDOW_CLIENT_TYPE_X11)
return &windows[i];
}
return NULL;
}
/**
* raise_window_relative_to_managed_windows:
*
* This function is used to avoid raising a window above popup
* menus and other such things.
*
* The key to the operation of this function is that we are expecting
* at most one window to be added at a time. If xwindow is newly added,
* then its own stack position will be too high (the frame window
* is created at the top of the stack), but if we ignore xwindow,
* then the *next* managed window in the stack will be a window that
* we've already stacked.
*
* We could generalize this and remove the assumption that windows
* are added one at a time by keeping an explicit ->stacked flag in
* MetaWindow.
*
* An alternate approach would be to reverse the stacking algorithm to
* work by placing each window above the others, and start by lowering
* a window to the bottom (instead of the current way, which works by
* placing each window below another and starting with a raise)
*/
static void
raise_window_relative_to_managed_windows (MetaScreen *screen,
const MetaStackWindow *window)
{
gulong serial = 0;
MetaStackWindow *sibling;
sibling = find_top_most_managed_window (screen, window);
if (!sibling)
{
if (window->any.type == META_WINDOW_CLIENT_TYPE_X11)
{
serial = XNextRequest (screen->display->xdisplay);
meta_error_trap_push (screen->display);
XLowerWindow (screen->display->xdisplay,
window->x11.xwindow);
meta_error_trap_pop (screen->display);
}
/* No sibling to use, just lower ourselves to the bottom
* to be sure we're below any override redirect windows.
*/
meta_stack_tracker_record_lower (screen->stack_tracker,
window,
serial);
return;
}
/* window is the topmost managed child */
meta_topic (META_DEBUG_STACK,
"Moving 0x%lx above topmost managed child window 0x%lx\n",
window->any.type == META_WINDOW_CLIENT_TYPE_X11 ? window->x11.xwindow: 0,
sibling->any.type == META_WINDOW_CLIENT_TYPE_X11 ? sibling->x11.xwindow: 0);
if (window->any.type == META_WINDOW_CLIENT_TYPE_X11)
{
XWindowChanges changes;
MetaStackWindow *x11_sibling = find_x11_sibling_downwards (screen, sibling);
serial = XNextRequest (screen->display->xdisplay);
if (x11_sibling)
{
changes.sibling = x11_sibling->x11.xwindow;
changes.stack_mode = Above;
meta_error_trap_push (screen->display);
XConfigureWindow (screen->display->xdisplay,
window->x11.xwindow,
CWSibling | CWStackMode,
&changes);
meta_error_trap_pop (screen->display);
}
else
{
/* No sibling to use, just lower ourselves to the bottom
* to be sure we're below any override redirect windows.
*/
meta_error_trap_push (screen->display);
XLowerWindow (screen->display->xdisplay,
window->x11.xwindow);
meta_error_trap_pop (screen->display);
}
}
meta_stack_tracker_record_raise_above (screen->stack_tracker,
window,
sibling,
serial);
}
/**
* stack_sync_to_server:
*
@ -1235,13 +1037,9 @@ static void
stack_sync_to_xserver (MetaStack *stack)
{
GArray *x11_stacked;
GArray *x11_root_children_stacked;
GArray *all_root_children_stacked; /* wayland OR x11 */
GList *tmp;
GArray *x11_hidden;
GArray *x11_hidden_stack_windows;
int n_override_redirect = 0;
MetaStackWindow guard_stack_window;
GArray *x11_hidden_stack_ids;
/* Bail out if frozen */
if (stack->freeze_count > 0)
@ -1251,42 +1049,29 @@ stack_sync_to_xserver (MetaStack *stack)
stack_ensure_sorted (stack);
/* Create stacked xwindow arrays.
* Painfully, "stacked" is in bottom-to-top order for the
* _NET hints, and "root_children_stacked" is in top-to-bottom
* order for XRestackWindows()
/* Create stacked xwindow arrays, in bottom-to-top order
*/
x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow));
x11_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
x11_hidden_stack_windows = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow));
x11_hidden = g_array_new (FALSE, FALSE, sizeof (Window));
/* The screen guard window sits above all hidden windows and acts as
* a barrier to input reaching these windows. */
g_array_append_val (x11_hidden, stack->screen->guard_window);
all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (guint64));
x11_hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (guint64));
meta_topic (META_DEBUG_STACK, "Top to bottom: ");
meta_push_no_msg_prefix ();
for (tmp = stack->sorted; tmp != NULL; tmp = tmp->next)
for (tmp = g_list_last(stack->sorted); tmp != NULL; tmp = tmp->prev)
{
MetaWindow *w = tmp->data;
Window top_level_window;
MetaStackWindow stack_window;
guint64 stack_id;
stack_window.any.type = w->client_type;
if (w->unmanaging)
continue;
meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
w->layer, w->stack_position, w->desc);
/* remember, stacked is in reverse order (bottom to top) */
if (w->override_redirect)
n_override_redirect++;
else
g_array_prepend_val (x11_stacked, w->xwindow);
g_array_append_val (x11_stacked, w->xwindow);
if (w->frame)
top_level_window = w->frame->xwindow;
@ -1294,9 +1079,9 @@ stack_sync_to_xserver (MetaStack *stack)
top_level_window = w->xwindow;
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
stack_window.x11.xwindow = top_level_window;
stack_id = top_level_window;
else
stack_window.wayland.meta_window = w;
stack_id = w->stamp;
/* We don't restack hidden windows along with the rest, though they are
* reflected in the _NET hints. Hidden windows all get pushed below
@ -1305,267 +1090,34 @@ stack_sync_to_xserver (MetaStack *stack)
{
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
{
MetaStackWindow stack_window;
guint64 stack_id = top_level_window;
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
stack_window.x11.xwindow = top_level_window;
g_array_append_val (x11_hidden_stack_windows, stack_window);
g_array_append_val (x11_hidden, top_level_window);
g_array_append_val (x11_hidden_stack_ids, stack_id);
}
continue;
}
g_array_append_val (all_root_children_stacked, stack_window);
/* build XRestackWindows() array from top to bottom */
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
g_array_append_val (x11_root_children_stacked, top_level_window);
g_array_append_val (all_root_children_stacked, stack_id);
}
meta_topic (META_DEBUG_STACK, "\n");
meta_pop_no_msg_prefix ();
/* All X windows should be in some stacking order */
if (x11_stacked->len != stack->xwindows->len - n_override_redirect)
meta_bug ("%u windows stacked, %u windows exist in stack\n",
x11_stacked->len, stack->xwindows->len);
/* The screen guard window sits above all hidden windows and acts as
* a barrier to input reaching these windows. */
g_array_append_val (x11_hidden_stack_ids, stack->screen->guard_window);
/* Sync to server */
meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
all_root_children_stacked->len);
meta_error_trap_push (stack->screen->display);
if (stack->last_all_root_children_stacked == NULL)
{
/* Just impose our stack, we don't know the previous state.
* This involves a ton of circulate requests and may flicker.
*/
meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n");
if (all_root_children_stacked->len > 1)
{
gulong serial = 0;
if (x11_root_children_stacked->len > 1)
{
serial = XNextRequest (stack->screen->display->xdisplay);
XRestackWindows (stack->screen->display->xdisplay,
(Window *) x11_root_children_stacked->data,
x11_root_children_stacked->len);
}
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
(MetaStackWindow *) all_root_children_stacked->data,
all_root_children_stacked->len,
serial);
}
}
else if (all_root_children_stacked->len > 0)
{
/* Try to do minimal window moves to get the stack in order */
/* A point of note: these arrays include frames not client windows,
* so if a client window has changed frame since last_root_children_stacked
* was saved, then we may have inefficiency, but I don't think things
* break...
*/
const MetaStackWindow *old_stack = (MetaStackWindow *) stack->last_all_root_children_stacked->data;
const MetaStackWindow *new_stack = (MetaStackWindow *) all_root_children_stacked->data;
const int old_len = stack->last_all_root_children_stacked->len;
const int new_len = all_root_children_stacked->len;
const MetaStackWindow *oldp = old_stack;
const MetaStackWindow *newp = new_stack;
const MetaStackWindow *old_end = old_stack + old_len;
const MetaStackWindow *new_end = new_stack + new_len;
Window last_xwindow = None;
const MetaStackWindow *last_window = NULL;
while (oldp != old_end &&
newp != new_end)
{
if (meta_stack_window_equal (oldp, newp))
{
/* Stacks are the same here, move on */
++oldp;
if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
last_xwindow = newp->x11.xwindow;
last_window = newp;
++newp;
}
else if ((oldp->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
meta_display_lookup_x_window (stack->screen->display,
oldp->x11.xwindow) == NULL) ||
(oldp->any.type == META_WINDOW_CLIENT_TYPE_WAYLAND &&
oldp->wayland.meta_window == NULL))
{
/* *oldp is no longer known to us (probably destroyed),
* so we can just skip it
*/
++oldp;
}
else
{
/* Move *newp below the last_window */
if (!last_window)
{
meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n",
newp->x11.xwindow);
raise_window_relative_to_managed_windows (stack->screen, newp);
}
else if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
last_xwindow == None)
{
/* In this case we have an X window that we need to
* put below a wayland window and this is the
* topmost X window. */
/* In X terms (because this is the topmost X window)
* we want to
* raise_window_relative_to_managed_windows() to
* ensure the X window is below override-redirect
* pop-up windows.
*
* In Wayland terms we just want to ensure
* newp is lowered below last_window (which
* notably doesn't require an X request because we
* know last_window isn't an X window).
*/
raise_window_relative_to_managed_windows (stack->screen, newp);
meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
newp, last_window,
0); /* no x request serial */
}
else
{
gulong serial = 0;
/* This means that if last_xwindow is dead, but not
* *newp, then we fail to restack *newp; but on
* unmanaging last_xwindow, we'll fix it up.
*/
meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
newp->any.type == META_WINDOW_CLIENT_TYPE_X11 ? newp->x11.xwindow : 0,
last_xwindow);
if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
{
XWindowChanges changes;
serial = XNextRequest (stack->screen->display->xdisplay);
changes.sibling = last_xwindow;
changes.stack_mode = Below;
XConfigureWindow (stack->screen->display->xdisplay,
newp->x11.xwindow,
CWSibling | CWStackMode,
&changes);
}
meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
newp, last_window,
serial);
}
if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
last_xwindow = newp->x11.xwindow;
last_window = newp;
++newp;
}
}
if (newp != new_end)
{
const MetaStackWindow *x_ref;
unsigned long serial = 0;
/* Restack remaining windows */
meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n",
(int) (new_end - newp));
/* rewind until we find the last stacked X window that we can use
* as a reference point for re-stacking remaining X windows */
if (newp != new_stack)
for (x_ref = newp - 1;
x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack;
x_ref--)
;
else
x_ref = new_stack;
/* If we didn't find an X window looking backwards then walk forwards
* through the remaining windows to find the first remaining X window
* instead. */
if (x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11)
{
for (x_ref = newp;
x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref < new_end;
x_ref++)
;
}
/* If there are any X windows remaining unstacked then restack them */
if (x_ref->any.type == META_WINDOW_CLIENT_TYPE_X11)
{
int i;
for (i = x11_root_children_stacked->len - 1; i; i--)
{
Window *reference = &g_array_index (x11_root_children_stacked, Window, i);
if (*reference == x_ref->x11.xwindow)
{
int n = x11_root_children_stacked->len - i;
/* There's no point restacking if there's only one X window */
if (n == 1)
break;
serial = XNextRequest (stack->screen->display->xdisplay);
XRestackWindows (stack->screen->display->xdisplay,
reference, n);
break;
}
}
}
/* We need to include an already-stacked window
* in the restack call, so we get in the proper position
* with respect to it.
*/
if (newp != new_stack)
newp = MIN (newp - 1, x_ref);
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
newp, new_end - newp,
serial);
}
}
/* Push hidden X windows to the bottom of the stack under the guard window */
guard_stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
guard_stack_window.x11.xwindow = stack->screen->guard_window;
meta_stack_tracker_record_lower (stack->screen->stack_tracker,
&guard_stack_window,
XNextRequest (stack->screen->display->xdisplay));
XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window);
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
(MetaStackWindow *)x11_hidden_stack_windows->data,
x11_hidden_stack_windows->len,
XNextRequest (stack->screen->display->xdisplay));
XRestackWindows (stack->screen->display->xdisplay,
(Window *)x11_hidden->data,
x11_hidden->len);
g_array_free (x11_hidden, TRUE);
g_array_free (x11_hidden_stack_windows, TRUE);
meta_error_trap_pop (stack->screen->display);
/* on error, a window was destroyed; it should eventually
* get removed from the stacking list when we unmanage it
* and we'll fix stacking at that time.
*/
meta_stack_tracker_restack_managed (stack->screen->stack_tracker,
(guint64 *)all_root_children_stacked->data,
all_root_children_stacked->len);
meta_stack_tracker_restack_at_bottom (stack->screen->stack_tracker,
(guint64 *)x11_hidden_stack_ids->data,
x11_hidden_stack_ids->len);
/* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */
@ -1585,14 +1137,7 @@ stack_sync_to_xserver (MetaStack *stack)
x11_stacked->len);
g_array_free (x11_stacked, TRUE);
if (stack->last_all_root_children_stacked)
free_last_all_root_children_stacked_cache (stack);
stack->last_all_root_children_stacked = all_root_children_stacked;
g_array_free (x11_root_children_stacked, TRUE);
/* That was scary... */
g_array_free (all_root_children_stacked, TRUE);
}
MetaWindow*
@ -1730,6 +1275,9 @@ get_default_focus_window (MetaStack *stack,
if (window->minimized)
continue;
if (window->unmanaging)
continue;
if (!(window->input || window->take_focus))
continue;

View File

@ -92,6 +92,7 @@ struct _MetaWindow
MetaDisplay *display;
MetaScreen *screen;
guint64 stamp;
const MetaMonitorInfo *monitor;
MetaWorkspace *workspace;
MetaWindowClientType client_type;
@ -652,9 +653,6 @@ void meta_window_set_transient_for (MetaWindow *window,
void meta_window_set_opacity (MetaWindow *window,
guint8 opacity);
void meta_window_set_custom_frame_extents (MetaWindow *window,
GtkBorder *extents);
void meta_window_handle_enter (MetaWindow *window,
guint32 timestamp,
guint root_x,

View File

@ -71,6 +71,10 @@
static int destroying_windows_disallowed = 0;
// Each window has a "stamp" which is a non-recycled 64-bit ID. They
// start after the end of the XID space so that, for stacking
// we can keep a guint64 that represents one or the other
static guint64 next_window_stamp = G_GUINT64_CONSTANT(0x100000000);
static void invalidate_work_areas (MetaWindow *window);
static void set_wm_state (MetaWindow *window);
@ -642,6 +646,7 @@ meta_window_class_init (MetaWindowClass *klass)
static void
meta_window_init (MetaWindow *self)
{
self->stamp = next_window_stamp++;
meta_prefs_add_listener (prefs_changed_callback, self);
}
@ -803,6 +808,8 @@ _meta_window_shared_new (MetaDisplay *display,
* type
*/
window->display = display;
meta_display_register_stamp (window->display, &window->stamp, window);
window->workspace = NULL;
window->sync_request_counter = None;
@ -1055,8 +1062,8 @@ _meta_window_shared_new (MetaDisplay *display,
if (window->initial_workspace_set)
{
gboolean on_all_workspaces;
MetaWorkspace *workspace;
gboolean on_all_workspaces = window->on_all_workspaces;
MetaWorkspace *workspace = NULL;
if (window->initial_workspace == (int) 0xFFFFFFFF)
{
@ -1070,15 +1077,13 @@ _meta_window_shared_new (MetaDisplay *display,
window->on_all_workspaces_requested = TRUE;
on_all_workspaces = TRUE;
workspace = NULL;
}
else
else if (!on_all_workspaces)
{
meta_topic (META_DEBUG_PLACEMENT,
"Window %s is initially on space %d\n",
window->desc, window->initial_workspace);
on_all_workspaces = FALSE;
workspace = meta_screen_get_workspace_by_index (window->screen,
window->initial_workspace);
}
@ -1092,9 +1097,9 @@ _meta_window_shared_new (MetaDisplay *display,
* but appear on other workspaces. override-redirect windows are part
* of no workspace.
*/
if (!window->override_redirect)
if (!window->override_redirect && window->workspace == NULL)
{
if (window->workspace == NULL && window->transient_for != NULL)
if (window->transient_for != NULL)
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on same workspace as parent %s\n",
@ -1105,7 +1110,15 @@ _meta_window_shared_new (MetaDisplay *display,
window->transient_for->workspace);
}
if (window->workspace == NULL)
if (window->on_all_workspaces)
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on all workspaces\n",
window->desc);
set_workspace_state (window, TRUE, NULL);
}
else
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on active workspace\n",
@ -1239,6 +1252,8 @@ meta_window_unmanage (MetaWindow *window,
meta_bug ("Tried to destroy window %s while destruction was not allowed\n",
window->desc);
meta_display_unregister_stamp (window->display, window->stamp);
window->unmanaging = TRUE;
if (meta_prefs_get_attach_modal_dialogs ())
@ -1296,9 +1311,7 @@ meta_window_unmanage (MetaWindow *window,
meta_topic (META_DEBUG_FOCUS,
"Focusing default window since we're unmanaging %s\n",
window->desc);
meta_workspace_focus_default_window (window->screen->active_workspace,
window,
timestamp);
meta_workspace_focus_default_window (window->screen->active_workspace, NULL, timestamp);
}
else
{
@ -2082,7 +2095,7 @@ windows_overlap (const MetaWindow *w1, const MetaWindow *w2)
static gboolean
window_would_be_covered (const MetaWindow *newbie)
{
MetaWorkspace *workspace = newbie->workspace;
MetaWorkspace *workspace = meta_window_get_workspace ((MetaWindow *)newbie);
GList *tmp, *windows;
windows = meta_workspace_list_windows (workspace);
@ -2609,6 +2622,9 @@ meta_window_maximize_internal (MetaWindow *window,
meta_window_recalc_features (window);
set_net_wm_state (window);
if (window->monitor->in_fullscreen)
meta_screen_queue_check_fullscreen (window->screen);
g_object_freeze_notify (G_OBJECT (window));
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MAXIMIZED_HORIZONTALLY]);
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MAXIMIZED_VERTICALLY]);
@ -3053,6 +3069,8 @@ meta_window_unmaximize_internal (MetaWindow *window,
meta_window_recalc_features (window);
set_net_wm_state (window);
if (!window->monitor->in_fullscreen)
meta_screen_queue_check_fullscreen (window->screen);
}
g_object_freeze_notify (G_OBJECT (window));
@ -4284,7 +4302,7 @@ meta_window_focus (MetaWindow *window,
* - workspace->windows is a list of windows that is located on
* that workspace.
*
* - If the window is on_all_workspaces, then then
* - If the window is on_all_workspaces, then
* window->workspace == NULL, but workspace->windows contains
* the window.
*/
@ -4306,7 +4324,8 @@ set_workspace_state (MetaWindow *window,
g_return_if_fail ((window->constructing && on_all_workspaces) || window->unmanaging);
if (on_all_workspaces == window->on_all_workspaces &&
workspace == window->workspace)
workspace == window->workspace &&
!window->constructing)
return;
if (window->workspace)
@ -4638,6 +4657,32 @@ meta_window_appears_focused_changed (MetaWindow *window)
meta_frame_queue_draw (window->frame);
}
static gboolean
should_propagate_focus_appearance (MetaWindow *window)
{
/* Parents of attached modal dialogs should appear focused. */
if (meta_window_is_attached_dialog (window))
return TRUE;
/* Parents of these sorts of override-redirect windows should
* appear focused. */
switch (window->type)
{
case META_WINDOW_DROPDOWN_MENU:
case META_WINDOW_POPUP_MENU:
case META_WINDOW_COMBO:
case META_WINDOW_TOOLTIP:
case META_WINDOW_NOTIFICATION:
case META_WINDOW_DND:
case META_WINDOW_OVERRIDE_OTHER:
return TRUE;
default:
break;
}
return FALSE;
}
/**
* meta_window_propagate_focus_appearance:
* @window: the window to start propagating from
@ -4661,7 +4706,7 @@ meta_window_propagate_focus_appearance (MetaWindow *window,
child = window;
parent = meta_window_get_transient_for (child);
while (parent && (!focused || meta_window_is_attached_dialog (child)))
while (parent && (!focused || should_propagate_focus_appearance (child)))
{
gboolean child_focus_state_changed;
@ -5378,7 +5423,7 @@ meta_window_shove_titlebar_onscreen (MetaWindow *window)
gboolean
meta_window_titlebar_is_onscreen (MetaWindow *window)
{
MetaRectangle titlebar_rect;
MetaRectangle titlebar_rect, frame_rect;
GList *onscreen_region;
gboolean is_onscreen;
@ -5393,6 +5438,11 @@ meta_window_titlebar_is_onscreen (MetaWindow *window)
/* Get the rectangle corresponding to the titlebar */
meta_window_get_titlebar_rect (window, &titlebar_rect);
/* Translate into screen coordinates */
meta_window_get_frame_rect (window, &frame_rect);
titlebar_rect.x = frame_rect.x;
titlebar_rect.y = frame_rect.y;
/* Run through the spanning rectangles for the screen and see if one of
* them overlaps with the titlebar sufficiently to consider it onscreen.
*/
@ -6712,7 +6762,7 @@ meta_window_set_demands_attention (MetaWindow *window)
other_window = stack->data;
stack = stack->next;
if (meta_window_located_on_workspace (other_window, window->workspace))
if (meta_window_located_on_workspace (other_window, workspace))
{
meta_window_get_frame_rect (other_window, &other_rect);
@ -7880,24 +7930,6 @@ meta_window_handle_ungrabbed_event (MetaWindow *window,
}
}
void
meta_window_set_custom_frame_extents (MetaWindow *window,
GtkBorder *extents)
{
if (extents)
{
window->has_custom_frame_extents = TRUE;
window->custom_frame_extents = *extents;
}
else
{
window->has_custom_frame_extents = FALSE;
memset (&window->custom_frame_extents, 0, sizeof (window->custom_frame_extents));
}
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
}
gboolean
meta_window_can_maximize (MetaWindow *window)
{

View File

@ -170,6 +170,7 @@ MetaWorkspace*
meta_workspace_new (MetaScreen *screen)
{
MetaWorkspace *workspace;
GSList *windows, *l;
workspace = g_object_new (META_TYPE_WORKSPACE, NULL);
@ -197,6 +198,13 @@ meta_workspace_new (MetaScreen *screen)
workspace->showing_desktop = FALSE;
/* make sure sticky windows are in our mru_list */
windows = meta_display_list_windows (screen->display, META_LIST_SORTED);
for (l = windows; l; l = l->next)
if (meta_window_located_on_workspace (l->data, workspace))
meta_workspace_add_window (workspace, l->data);
g_slist_free (windows);
return workspace;
}
@ -358,7 +366,7 @@ meta_workspace_relocate_windows (MetaWorkspace *workspace,
{
MetaWindow *window = l->data;
if (!window->override_redirect)
if (!window->on_all_workspaces)
meta_window_change_workspace (window, new_home);
}
@ -1159,11 +1167,8 @@ meta_workspace_focus_default_window (MetaWorkspace *workspace,
guint32 timestamp)
{
if (timestamp == CurrentTime)
{
meta_warning ("CurrentTime used to choose focus window; "
"focus window may not be correct.\n");
}
meta_warning ("CurrentTime used to choose focus window; "
"focus window may not be correct.\n");
if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK ||
!workspace->screen->display->mouse_mode)

View File

@ -37,6 +37,7 @@ Window meta_get_overlay_window (MetaScreen *screen);
GList *meta_get_window_actors (MetaScreen *screen);
ClutterActor *meta_get_window_group_for_screen (MetaScreen *screen);
ClutterActor *meta_get_top_window_group_for_screen (MetaScreen *screen);
ClutterActor *meta_get_feedback_group_for_screen (MetaScreen *screen);
void meta_disable_unredirect_for_screen (MetaScreen *screen);
void meta_enable_unredirect_for_screen (MetaScreen *screen);

View File

@ -22,10 +22,8 @@
#define META_BACKGROUND_ACTOR_H
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <meta/gradient.h>
#include <meta/screen.h>
#include <meta/meta-background.h>
#include <gsettings-desktop-schemas/gdesktop-enums.h>
@ -63,6 +61,15 @@ struct _MetaBackgroundActor
GType meta_background_actor_get_type (void);
ClutterActor *meta_background_actor_new (void);
ClutterActor *meta_background_actor_new (MetaScreen *screen,
int monitor);
void meta_background_actor_set_background (MetaBackgroundActor *self,
MetaBackground *background);
void meta_background_actor_set_vignette (MetaBackgroundActor *self,
gboolean enabled,
double brightness,
double sharpness);
#endif /* META_BACKGROUND_ACTOR_H */

View File

@ -0,0 +1,76 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* MetaBackgroundImageCache:
*
* Simple cache for background textures loaded from files
*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __META_BACKGROUND_IMAGE_H__
#define __META_BACKGROUND_IMAGE_H__
#include <glib-object.h>
#include <cogl/cogl.h>
#define META_TYPE_BACKGROUND_IMAGE (meta_background_image_get_type ())
#define META_BACKGROUND_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKGROUND_IMAGE, MetaBackgroundImage))
#define META_BACKGROUND_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_BACKGROUND_IMAGE, MetaBackgroundImageClass))
#define META_IS_BACKGROUND_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_BACKGROUND_IMAGE))
#define META_IS_BACKGROUND_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_BACKGROUND_IMAGE))
#define META_BACKGROUND_IMAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_BACKGROUND_IMAGE, MetaBackgroundImageClass))
/**
* MetaBackgroundImage:
*
* #MetaBackgroundImage is an object that represents a loaded or loading background image.
*/
typedef struct _MetaBackgroundImage MetaBackgroundImage;
typedef struct _MetaBackgroundImageClass MetaBackgroundImageClass;
GType meta_background_image_get_type (void);
gboolean meta_background_image_is_loaded (MetaBackgroundImage *image);
gboolean meta_background_image_get_success (MetaBackgroundImage *image);
CoglTexture *meta_background_image_get_texture (MetaBackgroundImage *image);
#define META_TYPE_BACKGROUND_IMAGE_CACHE (meta_background_image_cache_get_type ())
#define META_BACKGROUND_IMAGE_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKGROUND_IMAGE_CACHE, MetaBackgroundImageCache))
#define META_BACKGROUND_IMAGE_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_BACKGROUND_IMAGE_CACHE, MetaBackgroundImageCacheClass))
#define META_IS_BACKGROUND_IMAGE_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_BACKGROUND_IMAGE_CACHE))
#define META_IS_BACKGROUND_IMAGE_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_BACKGROUND_IMAGE_CACHE))
#define META_BACKGROUND_IMAGE_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_BACKGROUND_IMAGE_CACHE, MetaBackgroundImageCacheClass))
/**
* MetaBackgroundImageCache:
*
* #MetaBackgroundImageCache caches loading of textures for backgrounds; there's actually
* nothing background specific about it, other than it is tuned to work well for
* large images as typically are used for backgrounds.
*/
typedef struct _MetaBackgroundImageCache MetaBackgroundImageCache;
typedef struct _MetaBackgroundImageCacheClass MetaBackgroundImageCacheClass;
MetaBackgroundImageCache *meta_background_image_cache_get_default (void);
GType meta_background_image_cache_get_type (void);
MetaBackgroundImage *meta_background_image_cache_load (MetaBackgroundImageCache *cache,
const char *filename);
void meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
const char *filename);
#endif /* __META_BACKGROUND_IMAGE_H__ */

View File

@ -1,8 +1,8 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* meta-background.h: CoglTexture for paintnig the system background
* meta-background-actor.h: for painting the root window background
*
* Copyright 2013 Red Hat, Inc.
* Copyright 2010 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
@ -21,20 +21,16 @@
#ifndef META_BACKGROUND_H
#define META_BACKGROUND_H
#include <cogl/cogl.h>
#include <clutter/clutter.h>
#include <meta/gradient.h>
#include <meta/screen.h>
#include <gsettings-desktop-schemas/gdesktop-enums.h>
#include <meta/screen.h>
/**
* MetaBackground:
*
* This class handles loading a background from file, screenshot, or
* color scheme. The resulting object can be associated with one or
* more #MetaBackgroundActor objects to handle loading the background.
* This class handles tracking and painting the root window background.
* By integrating with #MetaWindowGroup we can avoid painting parts of
* the background that are obscured by other windows.
*/
#define META_TYPE_BACKGROUND (meta_background_get_type ())
@ -48,20 +44,6 @@ typedef struct _MetaBackground MetaBackground;
typedef struct _MetaBackgroundClass MetaBackgroundClass;
typedef struct _MetaBackgroundPrivate MetaBackgroundPrivate;
/**
* MetaBackgroundEffects:
* @META_BACKGROUND_EFFECTS_NONE: No effect
* @META_BACKGROUND_EFFECTS_VIGNETTE: Vignette
*
* Which effects to enable on the background
*/
typedef enum
{
META_BACKGROUND_EFFECTS_NONE = 0,
META_BACKGROUND_EFFECTS_VIGNETTE = 1 << 1,
} MetaBackgroundEffects;
struct _MetaBackgroundClass
{
/*< private >*/
@ -70,7 +52,6 @@ struct _MetaBackgroundClass
struct _MetaBackground
{
/*< private >*/
GObject parent;
MetaBackgroundPrivate *priv;
@ -78,33 +59,21 @@ struct _MetaBackground
GType meta_background_get_type (void);
MetaBackground *meta_background_new (MetaScreen *screen,
int monitor,
MetaBackgroundEffects effects);
MetaBackground *meta_background_copy (MetaBackground *self,
int monitor,
MetaBackgroundEffects effects);
MetaBackground *meta_background_new (MetaScreen *screen);
void meta_background_load_gradient (MetaBackground *self,
GDesktopBackgroundShading shading_direction,
ClutterColor *color,
ClutterColor *second_color);
void meta_background_load_color (MetaBackground *self,
ClutterColor *color);
void meta_background_load_file_async (MetaBackground *self,
const char *filename,
GDesktopBackgroundStyle style,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean meta_background_load_file_finish (MetaBackground *self,
GAsyncResult *result,
GError **error);
const char *meta_background_get_filename (MetaBackground *self);
GDesktopBackgroundStyle meta_background_get_style (MetaBackground *self);
GDesktopBackgroundShading meta_background_get_shading (MetaBackground *self);
const ClutterColor *meta_background_get_color (MetaBackground *self);
const ClutterColor *meta_background_get_second_color (MetaBackground *self);
void meta_background_set_color (MetaBackground *self,
ClutterColor *color);
void meta_background_set_gradient (MetaBackground *self,
GDesktopBackgroundShading shading_direction,
ClutterColor *color,
ClutterColor *second_color);
void meta_background_set_filename (MetaBackground *self,
const char *filename,
GDesktopBackgroundStyle style);
void meta_background_set_blend (MetaBackground *self,
const char *filename1,
const char *filename2,
double blend_factor,
GDesktopBackgroundStyle style);
#endif /* META_BACKGROUND_H */

View File

@ -28,7 +28,7 @@
#define META_TYPE_WORKSPACE (meta_workspace_get_type ())
#define META_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WORKSPACE, MetaWorkspace))
#define META_WORKSPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WORKSPACE, MetaWorkspaceClass))
#define META_IS_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_WORKSPACE_TYPE))
#define META_IS_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WORKSPACE))
#define META_IS_WORKSPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WORKSPACE))
#define META_WORKSPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WORKSPACE, MetaWorkspaceClass))

94
src/tests/README Normal file
View File

@ -0,0 +1,94 @@
This directory implements a framework for automated tests of Mutter. The basic
idea is that mutter-test-runner acts as the window manager and compositor, and
forks off instances of mutter-test-client to act as clients.
There's a simple scripting language for tests. A very small test would look like:
---
# Start up a new X11 client with the client id 1 (doesn't have to be an integer)
# Windows for this client will be referred to as 1/<window-id>
new_client 1 x11
# Create and show two windows - again the IDs don't have to be integers
create 1/1
show 1/1
create 1/2
show 1/2
# Wait for the commands we've executed in the clients to reach Mutter
wait
# Check that the windows are in the order we expect
assert_stacking 1/1 1/2
---
Running
=======
The tests are installed according to:
https://wiki.gnome.org/Initiatives/GnomeGoals/InstalledTests
if --enable-installed-tests is passed to configure. You can run them
uninstalled with:
cd src && make run-tests
Command reference
=================
The following commands are supported. Quoting and comments follow shell rules.
new_client <client-id> [wayland|x11]
Starts a client, connecting by either Wayland or X11. The client
will subsequently be known with the given client-id (an arbitrary
string)
quit_client <client-id>
Destroys all windows for the client, waits for that to be processed,
then instructs the client to exit.
create <client-id>/<window-id> [override|csd]
Creates a new window. For the X11 backend, the keyword 'override'
can be given to create an override-redirect and the keyword 'csd'
can be given to create a client-side decorated window.
show <client-id>/<window-id>
hide <client-id>/<window-id>
Ask the client to show (map) or hide (unmap) the given window
activate <client-id>/<window-id>
Ask the client to raise and focus the given window. This is currently a no-op
for Wayland, where this capability is not supported in the protocol.
local_activate <client-id>-<window-id>
The same as 'activate', but the operation is done directly inside Mutter
and works for both backends
raise <client-id>/<window-id>
lower <client-id>/<window-id>
Ask the client to raise or lower the given window ID. This is a no-op
for Wayland clients. (It's also considered discouraged, but supported, for
non-override-redirect X11 clients.)
minimize <client-id>/<window-id>
unminimize <client-id>/<window-id>
Ask the client to minimize or unminimize the given window ID. This older
term for this operation is "iconify".
destroy <client-id>/<window-id>
Destroy the given window
wait
Wait until all requests sent by Mutter to clients have been received by Mutter,
and then wait until all requests by Mutter have been processed by the X server.
assert_stacking <client-id>/<window-id> <client-id>/<window-id> ...
Assert that the list of client windows known to Mutter is as given and in
the given order, bottom to top. The character '|' can be present in the
list of windows to indicate the guard window that separates hidden and
visible windows. If '|' isn't present, the guard window is asserted to
be below all client windows.
This function also queries the X server stack and verifies that Mutter's
expectation of the X server stack matches reality.

View File

@ -0,0 +1,5 @@
[Test]
Description=All Mutter tests
Exec=@libexecdir@/installed-tests/mutter/mutter-test-runner --all
Type=session
Output=TAP

View File

@ -0,0 +1,22 @@
new_client 1 wayland
create 1/1
show 1/1
create 1/2
show 1/2
wait
assert_stacking 1/1 1/2
# Currently Wayland clients have no wait to bring themselves to the user's
# attention; gtk_window_present() is a no-op with the X11 backend of GTK+
# activate 1/1
# wait
# assert_stacking 1/2 1/1
# activate 1/2
# wait
# assert_stacking 1/1 1/2
local_activate 1/1
assert_stacking 1/2 1/1
local_activate 1/2
assert_stacking 1/1 1/2

View File

@ -0,0 +1,19 @@
new_client 1 x11
create 1/1
show 1/1
create 1/2
show 1/2
wait
assert_stacking 1/1 1/2
activate 1/1
wait
assert_stacking 1/2 1/1
activate 1/2
wait
assert_stacking 1/1 1/2
local_activate 1/1
assert_stacking 1/2 1/1
local_activate 1/2
assert_stacking 1/1 1/2

View File

@ -0,0 +1,22 @@
new_client 1 x11
create 1/1
show 1/1
create 1/2 csd
show 1/2
wait
assert_stacking 1/1 1/2
destroy 1/2
wait
assert_stacking 1/1
create 1/2 csd
show 1/2
create 1/3 csd
show 1/3
wait
assert_stacking 1/1 1/2 1/3
destroy 1/2
wait
assert_stacking 1/1 1/3

View File

@ -0,0 +1,18 @@
new_client 1 x11
create 1/1
show 1/1
create 1/2
show 1/2
wait
assert_stacking 1/1 1/2
minimize 1/2
wait
assert_stacking 1/2 | 1/1
# unminimize doesn't work for GTK+ currently, because GTK+ expects
# to be able to de-iconify with MapWindow, but the window is already
# mapped.
activate 1/2
wait
assert_stacking 1/1 1/2

View File

@ -0,0 +1,26 @@
new_client w wayland
new_client x x11
create w/1
show w/1
create w/2
show w/2
wait
create x/1
show x/1
create x/2
show x/2
wait
assert_stacking w/1 w/2 x/1 x/2
local_activate w/1
assert_stacking w/2 x/1 x/2 w/1
local_activate x/1
assert_stacking w/2 x/2 w/1 x/1
lower x/1
wait
assert_stacking x/1 w/2 x/2 w/1

View File

@ -0,0 +1,19 @@
new_client 1 x11
create 1/1
show 1/1
create 1/2 override
show 1/2
wait
assert_stacking 1/1 1/2
activate 1/1
wait
assert_stacking 1/1 1/2
lower 1/2
wait
assert_stacking 1/2 | 1/1
raise 1/2
wait
assert_stacking 1/1 1/2

385
src/tests/test-client.c Normal file
View File

@ -0,0 +1,385 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <gio/gunixinputstream.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <X11/extensions/sync.h>
char *client_id = "0";
static gboolean wayland;
GHashTable *windows;
static void read_next_line (GDataInputStream *in);
static GtkWidget *
lookup_window (const char *window_id)
{
GtkWidget *window = g_hash_table_lookup (windows, window_id);
if (!window)
g_print ("Window %s doesn't exist", window_id);
return window;
}
static void
process_line (const char *line)
{
GError *error = NULL;
int argc;
char **argv;
if (!g_shell_parse_argv (line, &argc, &argv, &error))
{
g_print ("error parsing command: %s", error->message);
g_error_free (error);
return;
}
if (argc < 1)
{
g_print ("Empty command");
goto out;
}
if (strcmp (argv[0], "create") == 0)
{
int i;
if (argc < 2)
{
g_print ("usage: create <id> [override|csd]");
goto out;
}
if (g_hash_table_lookup (windows, argv[1]))
{
g_print ("window %s already exists", argv[1]);
goto out;
}
gboolean override = FALSE;
gboolean csd = FALSE;
for (i = 2; i < argc; i++)
{
if (strcmp (argv[i], "override") == 0)
override = TRUE;
if (strcmp (argv[i], "csd") == 0)
csd = TRUE;
}
if (override && csd)
{
g_print ("override and csd keywords are exclusie");
goto out;
}
GtkWidget *window = gtk_window_new (override ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL);
g_hash_table_insert (windows, g_strdup (argv[1]), window);
if (csd)
{
GtkWidget *headerbar = gtk_header_bar_new ();
gtk_window_set_titlebar (GTK_WINDOW (window), headerbar);
gtk_widget_show (headerbar);
}
gtk_window_set_default_size (GTK_WINDOW (window), 100, 100);
gchar *title = g_strdup_printf ("test/%s/%s", client_id, argv[1]);
gtk_window_set_title (GTK_WINDOW (window), title);
g_free (title);
gtk_widget_realize (window);
if (!wayland)
{
/* The cairo xlib backend creates a window when initialized, which
* confuses our testing if it happens asynchronously the first
* time a window is painted. By creating an Xlib surface and
* destroying it, we force initialization at a more predictable time.
*/
GdkWindow *window_gdk = gtk_widget_get_window (window);
cairo_surface_t *surface = gdk_window_create_similar_surface (window_gdk,
CAIRO_CONTENT_COLOR,
1, 1);
cairo_surface_destroy (surface);
}
}
else if (strcmp (argv[0], "show") == 0)
{
if (argc != 2)
{
g_print ("usage: show <id>");
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
goto out;
gtk_widget_show (window);
}
else if (strcmp (argv[0], "hide") == 0)
{
if (argc != 2)
{
g_print ("usage: hide <id>");
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
goto out;
gtk_widget_hide (window);
}
else if (strcmp (argv[0], "activate") == 0)
{
if (argc != 2)
{
g_print ("usage: activate <id>");
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
goto out;
gtk_window_present (GTK_WINDOW (window));
}
else if (strcmp (argv[0], "raise") == 0)
{
if (argc != 2)
{
g_print ("usage: raise <id>");
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
goto out;
gdk_window_raise (gtk_widget_get_window (window));
}
else if (strcmp (argv[0], "lower") == 0)
{
if (argc != 2)
{
g_print ("usage: lower <id>");
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
goto out;
gdk_window_lower (gtk_widget_get_window (window));
}
else if (strcmp (argv[0], "destroy") == 0)
{
if (argc != 2)
{
g_print ("usage: destroy <id>");
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
goto out;
g_hash_table_remove (windows, argv[1]);
gtk_widget_destroy (window);
}
else if (strcmp (argv[0], "destroy_all") == 0)
{
if (argc != 1)
{
g_print ("usage: destroy_all");
goto out;
}
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, windows);
while (g_hash_table_iter_next (&iter, &key, &value))
gtk_widget_destroy (value);
g_hash_table_remove_all (windows);
}
else if (strcmp (argv[0], "sync") == 0)
{
if (argc != 1)
{
g_print ("usage: sync");
goto out;
}
gdk_display_sync (gdk_display_get_default ());
}
else if (strcmp (argv[0], "set_counter") == 0)
{
XSyncCounter counter;
int value;
if (argc != 3)
{
g_print ("usage: set_counter <counter> <value>");
goto out;
}
if (wayland)
{
g_print ("usage: set_counter can only be used for X11");
goto out;
}
counter = strtoul(argv[1], NULL, 10);
value = atoi(argv[2]);
XSyncValue sync_value;
XSyncIntToValue (&sync_value, value);
XSyncSetCounter (gdk_x11_display_get_xdisplay (gdk_display_get_default ()),
counter, sync_value);
}
else if (strcmp (argv[0], "minimize") == 0)
{
if (argc != 2)
{
g_print ("usage: minimize <id>");
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
goto out;
gtk_window_iconify (GTK_WINDOW (window));
}
else if (strcmp (argv[0], "unminimize") == 0)
{
if (argc != 2)
{
g_print ("usage: unminimize <id>");
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
goto out;
gtk_window_deiconify (GTK_WINDOW (window));
}
else
{
g_print ("Unknown command %s", argv[0]);
goto out;
}
g_print ("OK\n");
out:
g_strfreev (argv);
}
static void
on_line_received (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GDataInputStream *in = G_DATA_INPUT_STREAM (source);
GError *error = NULL;
gsize length;
char *line = g_data_input_stream_read_line_finish_utf8 (in, result, &length, &error);
if (line == NULL)
{
if (error != NULL)
g_printerr ("Error reading from stdin: %s\n", error->message);
gtk_main_quit ();
return;
}
process_line (line);
g_free (line);
read_next_line (in);
}
static void
read_next_line (GDataInputStream *in)
{
g_data_input_stream_read_line_async (in, G_PRIORITY_DEFAULT, NULL,
on_line_received, NULL);
}
const GOptionEntry options[] = {
{
"wayland", 0, 0, G_OPTION_ARG_NONE,
&wayland,
"Create a wayland client, not an X11 one",
NULL
},
{
"client-id", 0, 0, G_OPTION_ARG_STRING,
&client_id,
"Identifier used in Window titles for this client",
"CLIENT_ID",
},
{ NULL }
};
int
main(int argc, char **argv)
{
GOptionContext *context = g_option_context_new (NULL);
GError *error = NULL;
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context,
&argc, &argv, &error))
{
g_printerr ("%s", error->message);
return 1;
}
if (wayland)
gdk_set_allowed_backends ("wayland");
else
gdk_set_allowed_backends ("x11");
gtk_init (NULL, NULL);
windows = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
GInputStream *raw_in = g_unix_input_stream_new (0, FALSE);
GDataInputStream *in = g_data_input_stream_new (raw_in);
read_next_line (in);
gtk_main ();
return 0;
}

1158
src/tests/test-runner.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -573,6 +573,7 @@ meta_frames_manage_window (MetaFrames *frames,
frame->title = NULL;
frame->shape_applied = FALSE;
frame->prelit_control = META_FRAME_CONTROL_NONE;
frame->button_state = META_BUTTON_STATE_NORMAL;
meta_core_grab_buttons (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);

View File

@ -653,3 +653,11 @@ meta_ui_window_is_widget (MetaUI *ui,
else
return FALSE;
}
gboolean
meta_ui_window_is_dummy (MetaUI *ui,
Window xwindow)
{
GdkWindow *frames_window = gtk_widget_get_window (GTK_WIDGET (ui->frames));
return xwindow == gdk_x11_window_get_xid (frames_window);
}

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