Compare commits

...

105 Commits

Author SHA1 Message Date
Owen W. Taylor
c1bf1ec718 Bump version to 2.91.6 2011-02-01 12:25:14 -05:00
Owen W. Taylor
8b220079d0 Add ability to override workspace layout
A plugin that does workspace management on its on may want to set the
workspace layout without having to deal with putting a property
on the root window to be read back and parsed.

Add meta_screen_override_window_layout() that allows the same types
of layouts as _NET_DESKTOP_LAYOUT but without setting a property.

https://bugzilla.gnome.org/show_bug.cgi?id=640552
2011-02-01 11:34:56 -05:00
A S Alam
2df95970d9 update Punjabi Translation by A S Alam 2011-01-29 07:49:59 +05:30
Petr Kovar
a4569974a1 Update Czech translation 2011-01-28 20:36:04 +01:00
Fran Diéguez
c9d3ab772c QA of Galician translations 2011-01-27 03:18:07 +01:00
Owen W. Taylor
1a276a2ee5 Don't constantly restack hidden windows
A logic bug was resulting in the bottom hidden window (hidden means means
minimized or on a different workspace) continually being stacked above
the other hidden windows.

https://bugzilla.gnome.org/show_bug.cgi?id=640679
2011-01-26 17:02:17 -05:00
Owen W. Taylor
4c4c720dc1 Update _NET_CURRENT_DESKTOP on workspace removal
When we delete a workspace before the active workspace, we need
to upate the _NET_CURRENT_DESKTOP since the active workspace index
changes. To do this workspace.c:set_active_space_hint() is moved
to screen.c:meta_screen_set_active_workspace_hint() so that it
can be shared.

https://bugzilla.gnome.org/show_bug.cgi?id=640581
2011-01-26 17:02:17 -05:00
Florian Müllner
ad707be01e window-actor: Add "size-changed" signal
Emit a signal when the window size changes. While it is already
possible to connect to notify::allocation (or width/height), the
new signal is emitted outside a clutter allocation cycle, which
makes it more convenient when adjusting an actor's size/position
in response.
2011-01-25 21:32:20 +01:00
Owen W. Taylor
19d1f97600 Use G_GNUC_UNUSED to suppress warning
On gcc-4.4 (void)<expr> doesn't suppress warnings from
__attribute__((warn_unused_result)), so use
G_GNUC_UNUSED (which expands to __attribute__((unused))) instead
of removing a dummy variable.

https://bugzilla.gnome.org/show_bug.cgi?id=640508
2011-01-25 08:39:20 -05:00
Owen W. Taylor
4f079affea Fix set but not used variables
GCC 4.6 warns about variables that are set but never subsequently
used; fix all such instances.

https://bugzilla.gnome.org/show_bug.cgi?id=640469
2011-01-24 16:26:57 -05:00
Jasper St. Pierre
b4888103a6 display: Don't crash on Alt-Escape.
Fix a crash caused by 286160646b, where
we don't get a window when called from do_choose_window.

https://bugzilla.gnome.org/show_bug.cgi?id=640229
2011-01-24 19:38:55 +01:00
Daniel Nylander
e2364b82ef Updated Swedish translation 2011-01-23 10:23:31 +01:00
Kjartan Maraas
ba92645044 Updated Norwegian bokmål translation 2011-01-20 19:20:25 +01:00
Florian Müllner
2eb8b09b1a Restore the original tile state when a drag is cancelled
If a drag operation is cancelled, the dragged window should be
restored to its previous state/position. Implement this for tiled
states.

https://bugzilla.gnome.org/show_bug.cgi?id=639988
2011-01-20 18:49:48 +01:00
Florian Müllner
bca610ed50 Hide tile preview when cancelling a drag with Escape
As the tile preview is shown or hidden when a window is dragged
around, it may stick around if the drag operation is cancelled.
Make sure that the preview is hidden in this case.

https://bugzilla.gnome.org/show_bug.cgi?id=639988
2011-01-20 18:49:48 +01:00
Florian Müllner
53d6938b55 screen: Add a method to hide the tile preview unconditionally
Add meta_screen_tile_preview_hide() to hide the tile preview
independent from the tile state of the dragged window.

https://bugzilla.gnome.org/show_bug.cgi?id=639988
2011-01-20 18:49:48 +01:00
Florian Müllner
286160646b display: Keep track of the original tile state during drag
Drag operations may be cancelled, in which case the dragged window
should be restored to the position/state it had when the drag was
initialized. In order to do this for tiled states, the original
state has to be saved during the operation.

https://bugzilla.gnome.org/show_bug.cgi?id=639988
2011-01-20 18:49:48 +01:00
Florian Müllner
58068260a5 window: Make meta_window_tile() semi-public
The previous tiling state of a grabbed window should be restored
if the drag operation is cancelled (by hitting the Escape key).
This might involve to meta_window_tile(), so export the function
in window-private.h.

https://bugzilla.gnome.org/show_bug.cgi?id=639988
2011-01-20 18:49:48 +01:00
Chao-Hsiung Liao
57e8ce0d42 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2011-01-20 22:41:41 +08:00
Marios Zindilis
4ed1e8b3e2 Updated Greek translation 2011-01-19 18:12:00 +02:00
Adel Gadllah
8181454af5 MetaWindowActor: Add meta_window_actor_is_destroyed
Add a meta_window_actor_is_destroyed method which gets
whether the X window that the actor was displaying has been destroyed.

https://bugzilla.gnome.org/show_bug.cgi?id=639853
2011-01-18 19:35:41 +01:00
Gabor Kelemen
aa482e6d4f Updated Hungarian translation 2011-01-18 15:56:29 +01:00
Gabor Kelemen
0c9b2c6757 Fix a word repetition 2011-01-18 15:55:09 +01:00
Rui Matos
bbfc435a5c Teach meta_display_get_keybinding_action() about "Above_Tab" pseudo-keysym
https://bugzilla.gnome.org/show_bug.cgi?id=639532
2011-01-16 13:55:41 -05:00
Jasper St. Pierre
7e53094044 default plugin: Clean up unused n_workspaces variable.
n_workspaces is unused, which may cause compilation
errors under certain environments.

https://bugzilla.gnome.org/show_bug.cgi?id=639458
2011-01-16 13:54:31 -05:00
Florian Müllner
565f002bc4 ui: Port to GtkStyleContext
GtkStyle has been deprecated in favor of GtkStyleContext. A full
port would involve replacing GdkColor with GdkRGBA - leave this
out for the time being.

Bump the required version of GTK+.

https://bugzilla.gnome.org/show_bug.cgi?id=637761
2011-01-13 18:55:39 +01:00
Alexander Shopov
42fdd4f4d8 Updated Bulgarian translation 2011-01-12 23:45:34 +02:00
Khaled Hosny
217aa2898e Updated Arabic translation 2011-01-12 11:33:42 +02:00
Khaled Hosny
02e7c1bb2b Updated Arabic translation 2011-01-12 11:32:02 +02:00
Owen W. Taylor
bb57a8b6f3 Bump version to 2.91.5 2011-01-11 14:55:19 -05:00
Ivar Smolin
65d0f1a213 [l10n] Updated Estonian translation 2011-01-09 20:42:28 +02:00
Ivar Smolin
4344b7ba69 [l10n] Updated Estonian translation 2011-01-07 10:17:03 +02:00
Mattias Põldaru
b0072add05 [l10n] Updated Estonian translation 2011-01-06 19:25:30 +02:00
Owen W. Taylor
4ea00e102b Add an "Above_Tab" pseudo-keysym
We want switching between the windows of an application to be an easily
accessible operation. The convenient and memorable keybinding is the
key above the tab key - but the keysym for that key isn't consistent
across different keyboard layouts.

Add code that figures out the key from the XKB geometry and a magic
keysym name "Above_Tab" that refers to this key and switch
the default binding for cycle_group to <Alt>Above_Tab. (This will
have no effect for the normal case of getting the key binding from
GConf until this patch is applied to Metacity as well.)

https://bugzilla.gnome.org/show_bug.cgi?id=635569
2011-01-05 18:58:11 -05:00
Florian Müllner
ed99d12e8b theme: Add tiled_left/tiled_right frame states
It may be desirable for theme authors to treat side-by-side tiled
windows differently, for instance to give the edge-touching border
a width of 0, so add additional frame states for tiled windows.

https://bugzilla.gnome.org/show_bug.cgi?id=637330
2011-01-05 01:49:58 +01:00
Florian Müllner
0a2bb1b71c theme: Add background functions for single buttons
With the existing background functions, single buttons can not be
styled separately - on the left side, the style of the left button
is picked, and the right button's style on the right side.

As theme authors may want to add rounded corners to button groups
as a whole, it makes sense to treat the case of a single button in
a group differently.

https://bugzilla.gnome.org/show_bug.cgi?id=635683
2011-01-05 01:49:49 +01:00
Florian Müllner
4bc8c70c75 theme-parser: Use peek_required_version() for validation
When validating button functions and frame styles, the required
format version of the features used in the theme was compared to
the major version number of the supported format, limiting additions
to major theme format bumps.
Use peek_required_version() instead, so the minor version number
of the supported theme format is taken into account.

https://bugzilla.gnome.org/show_bug.cgi?id=635683
2011-01-04 21:40:38 +01:00
Florian Müllner
9f2581318a buttons: Fix background functions for non-default layouts
While the configured layout is taken into account for positioning
the buttons, the mapping from button function states to button
position states just assumed the default button layout in LTR
locales.
Do a proper mapping depending on the actual layout instead.

https://bugzilla.gnome.org/show_bug.cgi?id=635686
2011-01-04 19:00:30 +01:00
Nickolas Lloyd
48b9807c86 Remove option to turn compositing off
This patch removes the ability to disable compositing in mutter.  As
clutter compositing was the reason for the fork from metacity, turning
compositing off does not make sense.

https://bugzilla.gnome.org/show_bug.cgi?id=626875
2011-01-04 11:55:05 -05:00
Owen W. Taylor
0a821d2341 Update window->visible_to_compositor before calling into compositor
To deal with reentrancy from compositor plugins doing things like
moving windows between workspaces in an effect callback, update
the visible_to_compositor flag before calling into the compositor.

https://bugzilla.gnome.org/show_bug.cgi?id=613124
2011-01-04 11:46:44 -05:00
Owen W. Taylor
78092a404f If enabling a compositor with existing windows, set them visible as necessary
When a compositor is present, we keep the visibility state of the
compositor windows in sync with window->visible_to_compositor. We need
to do the same when enabling the compositor.

https://bugzilla.gnome.org/show_bug.cgi?id=613124
2011-01-04 11:40:41 -05:00
Andreas Mueller
d3df33ecdb Fix errors building for gles-systems (clutter-eglx)
* GL_TEXTURE_RECTANGLE_ARB not avaliable
* clutter_glx_texture_pixmap_using_extension / CLUTTER_GLX_TEXTURE_PIXMAP not avaliable

Signed-off-by: Andreas Mueller <schnitzeltony@gmx.de>
2011-01-04 11:27:16 -05:00
Adel Gadllah
1160744830 ui: Make sure we use the correct atom
We have to use gdk_x11_xatom_to_atom for display to make
it consistent with the surrounding code.
2010-12-24 18:07:03 +01:00
Owen W. Taylor
e884fc784e Bump GTK+ required version to 2.91.7 2010-12-23 17:22:16 -05:00
Gheyret T.Kenji
c16788f481 Added UG translation 2010-12-23 19:28:34 +01:00
Colin Walters
a1790fb6a8 configure: Increment version
This must have been unpushed after the release.
2010-12-23 11:58:43 -05:00
Florian Müllner
cbce4fd39d ui: Adapt to GDK API changes
Some API which was only meaningful on X11 was moved to the X11
backend and renamed accordingly, so adapt to those changes.

https://bugzilla.gnome.org/show_bug.cgi?id=637802
2010-12-22 13:39:36 -05:00
Nguyễn Thái Ngọc Duy
93c0620151 po/vi.po: merge translation updates from metacity 2010-12-19 17:58:05 +07:00
Emmanuele Bassi
2faf56947b Use GdkDeviceManager to get the core pointer
Commit 2c8c1c6df49 in gtk+ removed gdk_display_get_core_pointer().

The equivalent functionality can be achieved by using the
GdkDeviceManager to retrieve the client pointer device.
2010-12-17 17:12:01 +00:00
Florian Müllner
53777b133b ui: Disable multidevice support in GDK
GDK now uses XI2 by default, which conflicts with the X calls done
in mutter. Enforce the previous behavior.
2010-12-15 18:11:13 +01:00
Florian Müllner
594a69317a tiling: Reset maximized tile mode when unmaximizing
Maximized tiled windows end up with an inconsistent tile mode when
unmaximized by other means than dragging the window free (e.g.
using the unmaximize button or double clicking the title bar), so
reset the tile mode when unmaximizing.

This is not a problem for side-by-side tiling, as there are no
alternatives to dragging the window free.
2010-12-10 17:30:18 +01:00
Owen W. Taylor
3f9c375f1c MetaRegionIterator: avoid reading off end of rectangles array
Fix an off-by-one error in the check for "can we peek ahead to the next
rectangle".

https://bugzilla.gnome.org/show_bug.cgi?id=636491
2010-12-06 12:00:30 -05:00
Colin Walters
544c8edd9e theme: Handle new GTK+ states 2010-12-04 17:33:01 -05:00
Florian Müllner
654bd15319 tiling: Do not restore maximized tile state when unmaximizing
When a tiled window is maximized (e.g. by clicking the title bar
button), unmaximizing the window restores the tiled state. While
this is reasonable for side-by-side tiling, it is confusing for
"maximize" tiled windows, as unmaximization has no visible effect.

Change unmaximize to only restore the tiled state of side-by-side
tiled windows.
2010-12-04 21:35:15 +01:00
Florian Müllner
b85171007e window: Add a missing break
When adding maximize tiling, the cleaning of the tiled flag was
refactored to use a switch statement - a break was missed in the
process.
2010-12-04 21:35:15 +01:00
Matej Urbančič
f6ec33fa0c Updated Slovenian translation 2010-12-03 20:19:53 +01:00
Florian Müllner
7d0ff87cbe tiling: Fix "maximize" tile with no chrome at the top
The original patch triggered "maximize" when the window was dragged
to the top, so that the pointer was below or on the monitor edge and
above the work area's top.

If there's no chrome at the top of the monitor, so that monitor edge
and work area top fall together, the pointer cannot be moved above
the work area's top, so tiling was not triggered.
2010-12-03 02:45:41 +01:00
Benjamin Otte
8994e621f7 Replace some GDK X11 calls with future-proof ones
GTK is about to clean up its code and remove duplicate macros and
GdkDrawable usage. To prepare for that landing, we use the future-safe
versions of the same calls.

https://bugzilla.gnome.org/show_bug.cgi?id=636302
2010-12-03 00:17:42 +01:00
Benjamin Otte
d746591894 ui: Port testgradient example to GTK3
https://bugzilla.gnome.org/show_bug.cgi?id=636301
2010-12-03 00:17:42 +01:00
Florian Müllner
161c1088f9 tiling: disable "shake loose" feature when edge tiling
The old behavior of being able to shake loose a maximized window
overlaps with and is for the most part superceded by top edge tiling.

This commit changes the code to only enable shake loose behavior
when edge tiling is disabled.

https://bugzilla.gnome.org/show_bug.cgi?id=630548
2010-12-02 17:42:14 -05:00
Ray Strode
07c0471902 tiling: Add new "maximized" tile
In addition to the existing side-by-side tiling modes, this commit
adds a new "maximize" tiling mode.  It allows the user to maximize
their windows (in other words, tile with the edge panels) by dragging
their window to the top edge of the monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=630548
2010-12-02 17:11:11 -05:00
Ray Strode
5f4ee1b6e7 tiling: use META_WINDOW_TILED_SIDE_BY_SIDE in state check
The meta_window_handle_mouse_grab_op_event function ensures
the tile_mode variable is in a consistent state after a drag
op is finished.

The way this is current done is:

if (!window->maximized_vertically &&
    window->tile_mode != META_TILE_NONE)
  window->tile_mode = META_TILE_NONE;

While valid, it doesn't "read" as well as using the
META_WINDOW_TILED_SIDE_BY_SIDE macro, since the macro is specifically
about side-by-side tiling.

This commit just changes things to use the macro and to not bother
checking the tile mode (since if we just reset it anyway, then it doesn't
matter if the value is right or wrong to begin with).

https://bugzilla.gnome.org/show_bug.cgi?id=630548
2010-12-02 16:35:23 -05:00
Ray Strode
aa3a4a48e4 tiling: add side_by_side suffix to tile code
The meta_window_can_tile function and META_WINDOW_TILED
macro are pretty side-by-side tiling specific, so
rename them.

https://bugzilla.gnome.org/show_bug.cgi?id=630548
2010-12-02 16:35:23 -05:00
Ray Strode
0d27c9600f tiling: rename side-by-side tiling to edge tiling
Currently, the new tiling feature, supports side-by-side, horizontal
tiling when dragging windows to one of the vertical edges of a monitor.

Other types of tiling (on other monitor edges) are potentially useful,
though.

This commit renames the preference from side_by_side_tiling to
edge_tiling.

https://bugzilla.gnome.org/show_bug.cgi?id=630548
2010-12-02 16:35:23 -05:00
Milan Bouchet-Valat
1986b20499 Add (out) annotation and documentation to meta_window_get_outer_rectangle()
GObject introspection cannot detect that rect is an (out) parameter.
Also add a meaningful documentation for humans like us.
2010-12-02 00:06:42 +01:00
Owen W. Taylor
e7a10b0d6a Bump version to 2.91.3 2010-11-29 16:04:46 -05:00
Florian Müllner
6b98644c58 workspace: Consider text direction when switching
A direction parameter is passed to meta_compositor_switch_workspace(),
to indicate the direction of the switch depending on the workspace
layout.
In contrast to the switcher popup, this parameter does not take the
text direction of the locale into account. Change this, so that the
workspace switching animations move in the correct direction.

https://bugzilla.gnome.org/show_bug.cgi?id=636083
2010-11-29 21:42:58 +01:00
Dan Williams
5397335ae8 Fix builds with clutter < 1.5.2 2010-11-22 22:00:02 -06:00
Diego Escalante Urrelo
0b6d6e517d configure.in: it's git, not Subversion
Bug #635493
2010-11-22 20:04:22 -05:00
Owen W. Taylor
b031543f5a Fix updating overlay key keycode when keymap changes
overlay_key_combo needs the same treatment as other keycodes on a
change - we should always recompute it if we have a keysym not
a keycode, and not only if the keycode hasn't already been
computed.
2010-11-22 16:10:34 -05:00
Owen W. Taylor
c6be05f9d7 Unify keymap-reloading code branches
Simplify the keymap loading logic by unifying the different
branches; in the reorganization this patch fixes a bug where when
we got a MappingKeyboard event we wouldn't update virtual modifiers
correctly.

Based on a patch by Thomas Thurman <tthurman@gnome.org>

https://bugzilla.gnome.org/show_bug.cgi?id=565540
2010-11-22 16:02:03 -05:00
Derek Poon
cb88e0d052 Update keybindings when XKB keyboard layout changes
* Select for XKB keyboard notification events explicitly; since GTK+
  has selected for XKB events, delivery of old-school MappingNotify
  events is disabled.

* Fix a bug where once a keycode was loaded for a key binding,
  it would never be reassigned; we want to laod new keycodes for
  all bindings that have a key symbol rather than a fixed
  keycode.

[ With fixes from Owen W. Taylor <otaylor@fishsoup.net> ]

https://bugzilla.gnome.org/show_bug.cgi?id=565540
2010-11-22 16:02:03 -05:00
Owen W. Taylor
54e82daae2 configure.ac: move CFLAGS modifications after all tests
-Werror in CFLAGS was causing the check for GNU gettext in
AM_GNU_GLIB_GETTEXT to fail, resulting in .mo files in $libdir.

https://bugzilla.gnome.org/show_bug.cgi?id=635528
2010-11-22 10:49:55 -05:00
Adel Gadllah
1394c566eb [MetaWindowActor] Fix crash in shadow shape creation
Protect against shape_region or bounding_region being NULL in check_needs_shadow.

This can happen for short lived windows and result into a crash.

https://bugzilla.gnome.org/show_bug.cgi?id=635421
2010-11-21 19:57:42 +01:00
Yaron Shahrabani
3183d954a0 Updated Hebrew translation. 2010-11-21 12:58:12 +02:00
Kjartan Maraas
67b89e5c86 Updated Norwegian bokmål translation 2010-11-20 18:40:39 +01:00
Gheyret T.Kenji
c88c94886b Added UG translation 2010-11-20 12:06:01 +01:00
Fran Diéguez
c1f6902cb9 Updated Galician translations 2010-11-20 01:24:44 +01:00
Owen W. Taylor
8817e68926 Use COGL_MATERIAL_WRAP_MODE_* defines not COGL_PIPELINE_*
Since we aren't depending on Clutter 1.5 or using the new
CoglPipeline name elsewhere, we need to stick to the old
COGL_MATERIAL_WRAP_MODE_* names, which are provided with
compatibility defines in Clutter 1.4.

Pointed out by Rico Tzschichholz
2010-11-19 14:41:44 -05:00
Jorge González
b1868fb213 Updated Spanish translation 2010-11-19 13:46:08 +01:00
Owen W. Taylor
6260814285 Turn off background repeats for a full-size image
If we have repeats on for a full-sized image, then if the background
is displayed scaled (for example, in a desktop preview mode) then we
can get artifacts along the edge of the background where the repeat
of the opposite edge is blended in by bilinear scaling. So turn off
repeats when the screen and background image sizes match.

https://bugzilla.gnome.org/show_bug.cgi?id=634833
2010-11-18 13:58:37 -05:00
Owen W. Taylor
07e6c5aac2 Draw the root window background
Add code to track and draw the root window background. The advantage of doing
it here as compared to in a plugin is that we can use the visiblity smarts
of MetaWindowGroup to optimize out drawing the background when obscured.

If handling other than tracking the _XROOTPMAP_ID property is desired in the
future, more functionality like setting the background from a file or doing
cross-fades can be added.

The new background actor is exposed to plugins via meta_plugin_get_background_actor()
similar to other exposed actors to allow cloning the background for use in
other displays. The actual class is not installed for public consumption at
the moment since it has no useful methods.

https://bugzilla.gnome.org/show_bug.cgi?id=634833
2010-11-18 13:58:37 -05:00
Owen W. Taylor
0477a3066d Refactor "texture material" creation from MetaShadowFactory
Create new cogl-utils.[ch] and move a helper function from
MetaShadowFactory there as meta_create_texture_material(); this
allows us to create single-layer materials from different parts of
Mutter and have them share the same template material.

Also expose a function for creating a 1x1 texture of a given
color meta_create_color_texture_4ub().

https://bugzilla.gnome.org/show_bug.cgi?id=634833
2010-11-18 13:58:37 -05:00
Owen W. Taylor
59639909b1 MetaWindowGroup: further optimize paints by using current scissor
When in a partial stage paint, we can combine that with the visibility
information in MetaWindowGroup to further eliminate unneeded drawing.

Since there is no current Clutter API to access the current clip,
drop to using GL directly.

https://bugzilla.gnome.org/show_bug.cgi?id=634779
2010-11-18 13:58:36 -05:00
Adel Gadllah
64c37852b1 meta-actor-window: Use G_UNLIKELY for TFP check
This is just a microptimization, as we pretty much always use
TFP (and do the check every time we set a pixmap),
we can let gcc generate better code here.

https://bugzilla.gnome.org/show_bug.cgi?id=633002
2010-11-18 18:51:04 +01:00
Owen W. Taylor
bac668d287 Optimize out restacks that don't change actor order
For various reasons (mostly the stack tracker correctly predicting the
stacking order before getting events, but also because of the processing
that the compositor does to get the actor stacking order) the compositor
can be told to sync the stack when it has nothing to do. Detect this
at the last moment before actually telling Clutter to restack to avoid
triggering unnecessary redraws.

https://bugzilla.gnome.org/show_bug.cgi?id=634771
2010-11-18 10:07:38 -05:00
Owen W. Taylor
f372fa29b2 MetaStackTracker: Avoid queueing resync for obvious no-ops
Since we can't distinguish a ConfigureEvent that indicates a raise
from a ConfigureEvent that indicates a move, we get lots of
STACK_OP_RAISE_ABOVE events for windows that are already in the
right place in the stacking order. Avoid queueing a restack in that
case.

https://bugzilla.gnome.org/show_bug.cgi?id=634771
2010-11-18 09:54:44 -05:00
Owen W. Taylor
8b24711bba Omit shadows for fullscreen and maximized windows
Fullscreen and maximized windows never have visible shadows - the only
case where we would ever see them is if they bleed onto an adjacent
monitor and that looks bad.

It's small performance win to avoid computing them, and this also avoids
painting the top shadow for all maximized windows in GNOME Shell - since
the top panel isn't a X window, it doesn't factor into the computation
of what parts of windows are visible and maximized windows are computed
as having a top shadow.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:58 -05:00
Owen W. Taylor
d4c28fc5f5 Add meta_window_get_maximized() and meta_window_is_fullscreen()
These functions duplicate existing properties; they are added for
convenience and to avoid the GObject property code on some
performance critical painting paths.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:58 -05:00
Owen W. Taylor
ca5f2ac3ec Implement more accurate clipping of obscured shadows
Instead of making optimizing obscured shadows an all-or-none operation,
pass the clip region to meta_shadow_paint() and only paint the 9-slices
that are at least partially visible.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:58 -05:00
Owen W. Taylor
15f9590427 Report a correct paint volume for shadowed windows
Since we paint shadows directly now rather than using a child actor
in the ClutterGroup, we need to implement get_paint_volume() for
Clutter 1.5.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:58 -05:00
Owen W. Taylor
21a246eb42 Use a template material for shadows
To avoid unnecessary shader recompilation, use a root template material
for all shadows.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:58 -05:00
Owen W. Taylor
1bbaec81ce Make window shadows globally configurable
Instead of setting shadow parameters on individual windows, add the
idea of a "shadow class". Windows have default shadow classes based
on their frame and window type, which can be overriden by setting
the shadow-class property.

Each shadow class has separably configurable parameters for the
focused and unfocused state. New shadow classes can be defined with
arbitrary names.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:58 -05:00
Owen W. Taylor
7952feb48b Export meta_frame_type_to_string()
Frame types will form the bases of shadow classes, which are strings,
so export the to-string function so that we can do the conversion
uniformly.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:57 -05:00
Owen W. Taylor
52aebdf223 Add meta_window_get_frame_type()
Add a public function to get the frame type for a window; the
code is refactored from existing code in core.c.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:57 -05:00
Owen W. Taylor
6b16604c26 Export meta_window_appears_focused()
Move meta_window_appears_focused() into the public window.h so
we can use it to change the shadow type.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:57 -05:00
Owen W. Taylor
3c4d52732e Make MetaShadowFactory public
The basic MetaShadowFactory type is moved to a public header, while
the functions to fetch and paint shadows are kept private.
The public object will be used for configuration of shadows by
plugins.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:57 -05:00
Owen W. Taylor
d56d267f7d MetaShadowFactory: convert to a GObject
https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:57 -05:00
Owen W. Taylor
8eb31944a5 MetaShadowFactory: Add the ability to top-fade a shadow
For attached modal dialogs, we want the shadow to fade out at the top
as if the window was glued to the parent at the top. Add a
shadow-top-fade property to MetaWindowActor and the corresponding
parameter to meta_shadow_factory_get_shadow().

The internal implementation of MetaShadow is adjusted to work
in terms of an "inner border" and "outer border" instead of doing
the calculations in terms of an aggregate border and the spread
of the shadow. The old way of doing things gets clumsy when the
top_fade distance is added in as well.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:57 -05:00
Owen W. Taylor
ed2fbcd13a Add frame type for attached modal dialogs
Add a new frame type META_FRAME_TYPE_ATTACHED which is used for
attached modal dialogs.

The theme format version is bumped to 3.2, and attached windows
can have borders defined in a metacity-theme-3.xml as:

 <window version=">= 3.2" type="attached" style_set="[name]"/>

If no style is defined for "attached", drawing will fall back
to the "border" type.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:57 -05:00
Owen W. Taylor
9f4942e9a7 Make shadows pretty and configurable
The current shadow code just uses a single fixed texture (the Gaussian
blur of a rectangle with a fixed blur radius) for drawing all window
shadows. This patch adds the ability

* Implement efficient blurring of arbitrary regions by approximating
  a Gaussian blur with multiple box blurs.

* Detect when multiple windows can use the same shadow texture by
  converting their shape into a size-invariant MetaWindowShape.

* Add properties shadow-radius, shadow-x-offset, shadow-y-offset,
  shadow-opacity to allow the shadow for a window to be configured.

* Add meta_window_actor_paint() and draw the shadow directly
  from there rather than using a child actor.

* Remove TidyTextureFrame, which is no longer used

https://bugzilla.gnome.org/show_bug.cgi?id=592382
2010-11-18 09:47:56 -05:00
Gheyret T.Kenji
982a10ac44 Added UG translation 2010-11-14 00:06:42 +01:00
Gheyret T.Kenji
e59a9872b4 Added UG translation 2010-11-13 22:49:22 +01:00
Javier Jardón
9aedd32e01 Use gtk_button_box_new() instead gtk_[h|v]button_box_new() 2010-11-11 01:25:35 +01:00
Khaled Hosny
dd0ca4dd60 Updated Arabic translation 2010-11-09 03:40:15 +02:00
86 changed files with 12423 additions and 9795 deletions

View File

@@ -2,7 +2,7 @@ AC_PREREQ(2.50)
m4_define([mutter_major_version], [2])
m4_define([mutter_minor_version], [91])
m4_define([mutter_micro_version], [2])
m4_define([mutter_micro_version], [6])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@@ -61,73 +61,7 @@ AC_CHECK_SIZEOF(__int64)
## byte order
AC_C_BIGENDIAN
#### Warnings
# Stay command-line compatible with the gnome-common configure option. Here
# minimum/yes/maximum are the same, however.
AC_ARG_ENABLE(compile_warnings,
AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],[Turn on compiler warnings]),,
enable_compile_warnings=error)
changequote(,)dnl
if test "$enable_compile_warnings" != no ; then
if test "x$GCC" = "xyes"; then
case " $CFLAGS " in
*[\ \ ]-Wall[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wall" ;;
esac
# case " $CFLAGS " in
# *[\ \ ]-Wshadow[\ \ ]*) ;;
# *) CFLAGS="$CFLAGS -Wshadow" ;;
# esac
case " $CFLAGS " in
*[\ \ ]-Wchar-subscripts[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wchar-subscripts" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wmissing-declarations[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wmissing-declarations" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wmissing-prototypes[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wmissing-prototypes" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wnested-externs[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wnested-externs" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wpointer-arith[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wpointer-arith" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wcast-align[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wcast-align" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wsign-compare[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wsign-compare" ;;
esac
if test "$enable_compile_warnings" = error; then
case " $CFLAGS " in
*[\ \ ]-Werror[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Werror" ;;
esac
fi
fi
fi
changequote([,])dnl
GTK_MIN_VERSION=2.90.7
GTK_MIN_VERSION=2.91.7
CANBERRA_GTK=libcanberra-gtk3
CANBERRA_GTK_VERSION=0.26
@@ -518,6 +452,72 @@ AM_PATH_PYTHON([2.5])
# Use gnome-doc-utils:
GNOME_DOC_INIT([0.8.0])
#### Warnings (last since -Werror can disturb other tests)
# Stay command-line compatible with the gnome-common configure option. Here
# minimum/yes/maximum are the same, however.
AC_ARG_ENABLE(compile_warnings,
AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],[Turn on compiler warnings]),,
enable_compile_warnings=error)
changequote(,)dnl
if test "$enable_compile_warnings" != no ; then
if test "x$GCC" = "xyes"; then
case " $CFLAGS " in
*[\ \ ]-Wall[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wall" ;;
esac
# case " $CFLAGS " in
# *[\ \ ]-Wshadow[\ \ ]*) ;;
# *) CFLAGS="$CFLAGS -Wshadow" ;;
# esac
case " $CFLAGS " in
*[\ \ ]-Wchar-subscripts[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wchar-subscripts" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wmissing-declarations[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wmissing-declarations" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wmissing-prototypes[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wmissing-prototypes" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wnested-externs[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wnested-externs" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wpointer-arith[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wpointer-arith" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wcast-align[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wcast-align" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wsign-compare[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wsign-compare" ;;
esac
if test "$enable_compile_warnings" = error; then
case " $CFLAGS " in
*[\ \ ]-Werror[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Werror" ;;
esac
fi
fi
fi
changequote([,])dnl
AC_CONFIG_FILES([
Makefile
doc/Makefile
@@ -574,7 +574,7 @@ if expr $MUTTER_MINOR_VERSION % 2 > /dev/null ; then
stable_version=`expr $MUTTER_MINOR_VERSION - 1`
echo "This is the UNSTABLE branch of mutter"
echo -n "Use 2.$stable_version.x for stable "
echo "(gnome-2-$stable_version branch in Subversion)"
echo "(gnome-2-$stable_version branch in git)"
else
echo "This is the stable branch of mutter"
fi

View File

@@ -22,6 +22,24 @@ This document has separate sections for each format version. You may
want to read the document in reverse order, since the base features
are discussed under version 1.
New Features in Theme Format Version 3.3
========================================
Add two additional button background functions - left_single_background and
right_single_background - for button groups with just a single button.
There are now additional frame states to style left/right tiled windows
differently ("tiled_left", "tiled_right", "tiled_left_and_shaded",
"tiled_right_and_shaded").
New Features in Theme Format Version 3.2
========================================
A new window type 'attached' is added for modal dialogs which are
attached to their parent window. (When the attach_modal_dialogs preference
is turned on.) If no style is defined for the 'attached' window type,
the 'border' window type will be used instead.
New Features in Theme Format Version 3.1
========================================

View File

@@ -82,6 +82,7 @@ te
th
tk
tr
ug
uk
vi
wa

2204
po/ar.po

File diff suppressed because it is too large Load Diff

527
po/bg.po

File diff suppressed because it is too large Load Diff

368
po/cs.po

File diff suppressed because it is too large Load Diff

598
po/el.po

File diff suppressed because it is too large Load Diff

935
po/es.po

File diff suppressed because it is too large Load Diff

2432
po/et.po

File diff suppressed because it is too large Load Diff

573
po/gl.po

File diff suppressed because it is too large Load Diff

460
po/he.po

File diff suppressed because it is too large Load Diff

584
po/hu.po

File diff suppressed because it is too large Load Diff

459
po/nb.po

File diff suppressed because it is too large Load Diff

689
po/pa.po

File diff suppressed because it is too large Load Diff

564
po/sl.po

File diff suppressed because it is too large Load Diff

906
po/sv.po

File diff suppressed because it is too large Load Diff

1841
po/ug.po Normal file

File diff suppressed because it is too large Load Diff

1384
po/vi.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -21,13 +21,19 @@ mutter_SOURCES= \
core/boxes.c \
core/boxes-private.h \
include/boxes.h \
compositor/cogl-utils.c \
compositor/cogl-utils.h \
compositor/compositor.c \
compositor/compositor-private.h \
compositor/meta-background-actor.c \
compositor/meta-background-actor.h \
compositor/meta-module.c \
compositor/meta-module.h \
compositor/meta-plugin.c \
compositor/meta-plugin-manager.c \
compositor/meta-plugin-manager.h \
compositor/meta-shadow-factory.c \
compositor/meta-shadow-factory-private.h \
compositor/meta-shaped-texture.c \
compositor/meta-shaped-texture.h \
compositor/meta-texture-tower.c \
@@ -36,14 +42,16 @@ mutter_SOURCES= \
compositor/meta-window-actor-private.h \
compositor/meta-window-group.c \
compositor/meta-window-group.h \
compositor/shadow.c \
compositor/shadow.h \
compositor/tidy/tidy-texture-frame.c \
compositor/tidy/tidy-texture-frame.h \
compositor/meta-window-shape.c \
compositor/meta-window-shape.h \
compositor/region-utils.c \
compositor/region-utils.h \
include/compositor.h \
include/meta-plugin.h \
include/meta-shadow-factory.h \
include/meta-window-actor.h \
include/compositor-mutter.h \
core/above-tab-keycode.c \
core/constraints.c \
core/constraints.h \
core/core.c \
@@ -167,6 +175,7 @@ libmutterinclude_base_headers = \
include/group.h \
include/keybindings.h \
include/meta-plugin.h \
include/meta-shadow-factory.h \
include/meta-window-actor.h
# Excluded from scanning for introspection but installed

104
src/compositor/cogl-utils.c Normal file
View File

@@ -0,0 +1,104 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Utilities for use with Cogl
*
* Copyright 2010 Red Hat, Inc.
* Copyright 2010 Intel Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "cogl-utils.h"
/**
* meta_create_color_texture_4ub:
* @red:
* @green:
* @blue:
* @alpha:
*
* Creates a texture that is a single pixel with the specified
* unpremultiplied color components.
*
* Return value: (transfer full): a newly created Cogl texture
*/
CoglHandle
meta_create_color_texture_4ub (guint8 red,
guint8 green,
guint8 blue,
guint8 alpha)
{
CoglColor color;
guint8 pixel[4];
cogl_color_set_from_4ub (&color, red, green, blue, alpha);
cogl_color_premultiply (&color);
pixel[0] = cogl_color_get_red_byte (&color);
pixel[1] = cogl_color_get_green_byte (&color);
pixel[2] = cogl_color_get_blue_byte (&color);
pixel[3] = cogl_color_get_alpha_byte (&color);
return cogl_texture_new_from_data (1, 1,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_ANY,
4, pixel);
}
/* Based on gnome-shell/src/st/st-private.c:_st_create_texture_material.c */
/**
* meta_create_texture_material:
* @src_texture: (allow-none): texture to use initially for the layer
*
* Creates a material with a single layer. Using a common template
* allows sharing a shader for different uses in Mutter. To share the same
* shader with all other materials that are just texture plus opacity
* would require Cogl fixes.
* (See http://bugzilla.clutter-project.org/show_bug.cgi?id=2425)
*
* Return value: (transfer full): a newly created Cogl material
*/
CoglHandle
meta_create_texture_material (CoglHandle src_texture)
{
static CoglHandle texture_material_template = COGL_INVALID_HANDLE;
CoglHandle material;
/* We use a material that has a dummy texture as a base for all
texture materials. The idea is that only the Cogl texture object
would be different in the children so it is likely that Cogl will
be able to share GL programs between all the textures. */
if (G_UNLIKELY (texture_material_template == COGL_INVALID_HANDLE))
{
CoglHandle dummy_texture;
dummy_texture = meta_create_color_texture_4ub (0xff, 0xff, 0xff, 0xff);
texture_material_template = cogl_material_new ();
cogl_material_set_layer (texture_material_template, 0, dummy_texture);
cogl_handle_unref (dummy_texture);
}
material = cogl_material_copy (texture_material_template);
if (src_texture != COGL_INVALID_HANDLE)
cogl_material_set_layer (material, 0, src_texture);
return material;
}

View File

@@ -0,0 +1,34 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Utilities for use with Cogl
*
* 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
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef __META_COGL_UTILS_H__
#define __META_COGL_UTILS_H__
#include <cogl/cogl.h>
CoglHandle meta_create_color_texture_4ub (guint8 red,
guint8 green,
guint8 blue,
guint8 alpha);
CoglHandle meta_create_texture_material (CoglHandle src_texture);
#endif /* __META_COGL_UTILS_H__ */

View File

@@ -35,6 +35,7 @@ struct _MetaCompScreen
MetaScreen *screen;
ClutterActor *stage, *window_group, *overlay_group;
ClutterActor *background_actor;
ClutterActor *hidden_group;
GList *windows;
GHashTable *windows_by_xid;

View File

@@ -11,8 +11,10 @@
#include "compositor-mutter.h"
#include "xprops.h"
#include "prefs.h"
#include "meta-shadow-factory.h"
#include "meta-window-actor-private.h"
#include "meta-window-group.h"
#include "meta-background-actor.h"
#include "../core/window-private.h" /* to check window->hidden */
#include "../core/display-private.h" /* for meta_display_lookup_x_window() */
#include <X11/extensions/shape.h>
@@ -33,7 +35,7 @@ composite_at_least_version (MetaDisplay *display, int maj, int min)
return (major > maj || (major == maj && minor >= min));
}
static void sync_actor_stacking (GList *windows);
static void sync_actor_stacking (MetaCompScreen *info);
static void
meta_finish_workspace_switch (MetaCompScreen *info)
@@ -47,7 +49,7 @@ meta_finish_workspace_switch (MetaCompScreen *info)
/*
* Fix up stacking order in case the plugin messed it up.
*/
sync_actor_stacking (info->windows);
sync_actor_stacking (info);
/* printf ("... FINISHED DESKTOP SWITCH\n"); */
@@ -86,7 +88,7 @@ add_win (MetaWindow *window)
meta_window_actor_new (window);
sync_actor_stacking (info->windows);
sync_actor_stacking (info);
}
static void
@@ -135,6 +137,22 @@ process_property_notify (MetaCompositor *compositor,
{
MetaWindowActor *window_actor;
if (event->atom == compositor->atom_x_root_pixmap)
{
GSList *l;
for (l = meta_display_get_screens (compositor->display); l; l = l->next)
{
MetaScreen *screen = l->data;
if (event->window == meta_screen_get_xroot (screen))
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
meta_background_actor_update (META_BACKGROUND_ACTOR (info->background_actor));
return;
}
}
}
if (window == NULL)
return;
@@ -235,6 +253,27 @@ meta_get_window_group_for_screen (MetaScreen *screen)
return info->window_group;
}
/**
* meta_get_background_actor_for_screen:
* @screen: a #MetaScreen
*
* Gets the actor that draws the root window background under the windows.
* The root window background automatically tracks the image or color set
* by the environment.
*
* Returns: (transfer none): The background actor corresponding to @screen
*/
ClutterActor *
meta_get_background_actor_for_screen (MetaScreen *screen)
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
if (!info)
return NULL;
return info->background_actor;
}
/**
* meta_get_window_actors:
* @screen: a #MetaScreen
@@ -493,9 +532,14 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
XSelectInput (xdisplay, xwin, event_mask);
info->window_group = meta_window_group_new (screen);
info->background_actor = meta_background_actor_new (screen);
info->overlay_group = clutter_group_new ();
info->hidden_group = clutter_group_new ();
clutter_container_add (CLUTTER_CONTAINER (info->window_group),
info->background_actor,
NULL);
clutter_container_add (CLUTTER_CONTAINER (info->stage),
info->window_group,
info->overlay_group,
@@ -826,18 +870,73 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
}
static void
sync_actor_stacking (GList *windows)
sync_actor_stacking (MetaCompScreen *info)
{
GList *children;
GList *tmp;
GList *old;
gboolean reordered;
/* NB: The first entry in the list is stacked the lowest */
/* NB: The first entries in the lists are stacked the lowest */
for (tmp = g_list_last (windows); tmp != NULL; tmp = tmp->prev)
/* Restacking will trigger full screen redraws, so it's worth a
* little effort to make sure we actually need to restack before
* we go ahead and do it */
children = clutter_container_get_children (CLUTTER_CONTAINER (info->window_group));
reordered = FALSE;
old = children;
/* We allow for actors in the window group other than the actors we
* know about, but it's up to a plugin to try and keep them stacked correctly
* (we really need extra API to make that reliable.)
*/
/* Of the actors we know, the bottom actor should be the background actor */
while (old && old->data != info->background_actor && !META_IS_WINDOW_ACTOR (old->data))
old = old->next;
if (old == NULL || old->data != info->background_actor)
{
reordered = TRUE;
goto done_with_check;
}
/* Then the window actors should follow in sequence */
old = old->next;
for (tmp = info->windows; tmp != NULL; tmp = tmp->next)
{
while (old && !META_IS_WINDOW_ACTOR (old->data))
old = old->next;
/* old == NULL: someone reparented a window out of the window group,
* order undefined, always restack */
if (old == NULL || old->data != tmp->data)
{
reordered = TRUE;
goto done_with_check;
}
old = old->next;
}
done_with_check:
g_list_free (children);
if (!reordered)
return;
for (tmp = g_list_last (info->windows); tmp != NULL; tmp = tmp->prev)
{
MetaWindowActor *window_actor = tmp->data;
clutter_actor_lower_bottom (CLUTTER_ACTOR (window_actor));
}
clutter_actor_lower_bottom (info->background_actor);
}
void
@@ -875,7 +974,10 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
if (old_window->hidden &&
!meta_window_actor_effect_in_progress (old_actor))
old_stack = g_list_delete_link (old_stack, old_stack);
{
old_stack = g_list_delete_link (old_stack, old_stack);
old_actor = NULL;
}
else
break;
}
@@ -926,7 +1028,7 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
old_stack = g_list_remove (old_stack, actor);
}
sync_actor_stacking (info->windows);
sync_actor_stacking (info);
}
void
@@ -983,6 +1085,8 @@ meta_compositor_sync_screen_size (MetaCompositor *compositor,
clutter_actor_set_size (info->stage, width, height);
meta_background_actor_screen_size_changed (META_BACKGROUND_ACTOR (info->background_actor));
meta_verbose ("Changed size for stage on screen %d to %dx%d\n",
meta_screen_get_screen_number (screen),
width, height);
@@ -1017,6 +1121,26 @@ meta_repaint_func (gpointer data)
return TRUE;
}
static void
on_shadow_factory_changed (MetaShadowFactory *factory,
MetaCompositor *compositor)
{
GSList *screens = meta_display_get_screens (compositor->display);
GList *l;
GSList *sl;
for (sl = screens; sl; sl = sl->next)
{
MetaScreen *screen = sl->data;
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
if (!info)
continue;
for (l = info->windows; l; l = l->next)
meta_window_actor_invalidate_shadow (l->data);
}
}
/**
* meta_compositor_new: (skip)
*
@@ -1047,6 +1171,11 @@ meta_compositor_new (MetaDisplay *display)
XInternAtoms (xdisplay, atom_names, G_N_ELEMENTS (atom_names),
False, atoms);
g_signal_connect (meta_shadow_factory_get_default (),
"changed",
G_CALLBACK (on_shadow_factory_changed),
compositor);
compositor->atom_x_root_pixmap = atoms[0];
compositor->atom_x_set_root = atoms[1];
compositor->atom_net_wm_window_opacity = atoms[2];

View File

@@ -0,0 +1,414 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* meta-background-actor.c: Actor for painting the root window background
*
* Copyright 2009 Sander Dijkhuis
* 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
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Portions adapted from gnome-shell/src/shell-global.c
*/
#include <config.h>
#define COGL_ENABLE_EXPERIMENTAL_API
#include <cogl/cogl-texture-pixmap-x11.h>
#include <X11/Xatom.h>
#include "cogl-utils.h"
#include "compositor-private.h"
#include "errors.h"
#include "meta-background-actor.h"
struct _MetaBackgroundActorClass
{
ClutterActorClass parent_class;
};
struct _MetaBackgroundActor
{
ClutterActor parent;
CoglHandle material;
MetaScreen *screen;
cairo_region_t *visible_region;
float texture_width;
float texture_height;
guint have_pixmap : 1;
};
G_DEFINE_TYPE (MetaBackgroundActor, meta_background_actor, CLUTTER_TYPE_ACTOR);
static void
update_wrap_mode (MetaBackgroundActor *self)
{
int width, height;
CoglMaterialWrapMode wrap_mode;
meta_screen_get_size (self->screen, &width, &height);
/* We turn off repeating when we have a full-screen pixmap to keep from
* getting artifacts from one side of the image sneaking into the other
* side of the image via bilinear filtering.
*/
if (width == self->texture_width && height == self->texture_height)
wrap_mode = COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE;
else
wrap_mode = COGL_MATERIAL_WRAP_MODE_REPEAT;
cogl_material_set_layer_wrap_mode (self->material, 0, wrap_mode);
}
static void
set_texture (MetaBackgroundActor *self,
CoglHandle texture)
{
MetaDisplay *display;
display = meta_screen_get_display (self->screen);
/* This may trigger destruction of an old texture pixmap, which, if
* the underlying X pixmap is already gone has the tendency to trigger
* X errors inside DRI. For safety, trap errors */
meta_error_trap_push (display);
cogl_material_set_layer (self->material, 0, texture);
meta_error_trap_pop (display);
self->texture_width = cogl_texture_get_width (texture);
self->texture_height = cogl_texture_get_height (texture);
update_wrap_mode (self);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
/* Sets our material to paint with a 1x1 texture of the stage's background
* color; doing this when we have no pixmap allows the application to turn
* off painting the stage. There might be a performance benefit to
* painting in this case with a solid color, but the normal solid color
* case is a 1x1 root pixmap, so we'd have to reverse-engineer that to
* actually pick up the (small?) performance win. This is just a fallback.
*/
static void
set_texture_to_stage_color (MetaBackgroundActor *self)
{
ClutterActor *stage = meta_get_stage_for_screen (self->screen);
ClutterColor color;
CoglHandle texture;
clutter_stage_get_color (CLUTTER_STAGE (stage), &color);
texture = meta_create_color_texture_4ub (color.red, color.green,
color.blue, 0xff);
set_texture (self, texture);
cogl_handle_unref (texture);
}
static void
on_notify_stage_color (GObject *stage,
GParamSpec *pspec,
MetaBackgroundActor *self)
{
if (!self->have_pixmap)
set_texture_to_stage_color (self);
}
static void
meta_background_actor_dispose (GObject *object)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
meta_background_actor_set_visible_region (self, NULL);
if (self->material != COGL_INVALID_HANDLE)
{
cogl_handle_unref (self->material);
self->material = COGL_INVALID_HANDLE;
}
if (self->screen != NULL)
{
ClutterActor *stage = meta_get_stage_for_screen (self->screen);
g_signal_handlers_disconnect_by_func (stage,
(gpointer) on_notify_stage_color,
self);
self->screen = NULL;
}
}
static void
meta_background_actor_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
int width, height;
meta_screen_get_size (self->screen, &width, &height);
if (min_width_p)
*min_width_p = width;
if (natural_width_p)
*natural_width_p = height;
}
static void
meta_background_actor_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
int width, height;
meta_screen_get_size (self->screen, &width, &height);
if (min_height_p)
*min_height_p = height;
if (natural_height_p)
*natural_height_p = height;
}
static void
meta_background_actor_paint (ClutterActor *actor)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
int width, height;
meta_screen_get_size (self->screen, &width, &height);
cogl_set_source (self->material);
if (self->visible_region)
{
int n_rectangles = cairo_region_num_rectangles (self->visible_region);
int i;
for (i = 0; i < n_rectangles; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (self->visible_region, i, &rect);
cogl_rectangle_with_texture_coords (rect.x, rect.y,
rect.x + rect.width, rect.y + rect.height,
rect.x / self->texture_width,
rect.y / self->texture_height,
(rect.x + rect.width) / self->texture_width,
(rect.y + rect.height) / self->texture_height);
}
}
else
{
cogl_rectangle_with_texture_coords (0.0f, 0.0f,
width, height,
0.0f, 0.0f,
width / self->texture_width,
height / self->texture_height);
}
}
#if CLUTTER_CHECK_VERSION(1, 5, 2)
static gboolean
meta_background_actor_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
int width, height;
meta_screen_get_size (self->screen, &width, &height);
clutter_paint_volume_set_width (volume, width);
clutter_paint_volume_set_height (volume, height);
return TRUE;
}
#endif
static void
meta_background_actor_class_init (MetaBackgroundActorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
object_class->dispose = meta_background_actor_dispose;
actor_class->get_preferred_width = meta_background_actor_get_preferred_width;
actor_class->get_preferred_height = meta_background_actor_get_preferred_height;
actor_class->paint = meta_background_actor_paint;
#if CLUTTER_CHECK_VERSION(1, 5, 2)
actor_class->get_paint_volume = meta_background_actor_get_paint_volume;
#endif
}
static void
meta_background_actor_init (MetaBackgroundActor *background_actor)
{
}
/**
* @screen: the #MetaScreen
* meta_background_actor_new:
*
* Creates a new actor to draw the background for the given screen.
*
* Return value: (transfer none): the newly created background actor
*/
ClutterActor *
meta_background_actor_new (MetaScreen *screen)
{
MetaBackgroundActor *self;
ClutterActor *stage;
g_return_val_if_fail (META_IS_SCREEN (screen), NULL);
self = g_object_new (META_TYPE_BACKGROUND_ACTOR, NULL);
self->screen = screen;
self->material = meta_create_texture_material (NULL);
cogl_material_set_layer_wrap_mode (self->material, 0,
COGL_MATERIAL_WRAP_MODE_REPEAT);
stage = meta_get_stage_for_screen (self->screen);
g_signal_connect (stage, "notify::color",
G_CALLBACK (on_notify_stage_color), self);
meta_background_actor_update (self);
return CLUTTER_ACTOR (self);
}
/**
* meta_background_actor_update:
* @self: a #MetaBackgroundActor
*
* Refetches the _XROOTPMAP_ID property for the root window and updates
* the contents of the background actor based on that. There's no attempt
* to optimize out pixmap values that don't change (since a root pixmap
* could be replaced by with another pixmap with the same ID under some
* circumstances), so this should only be called when we actually receive
* a PropertyNotify event for the property.
*/
void
meta_background_actor_update (MetaBackgroundActor *self)
{
MetaDisplay *display;
MetaCompositor *compositor;
Atom type;
int format;
gulong nitems;
gulong bytes_after;
guchar *data;
Pixmap root_pixmap_id;
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
display = meta_screen_get_display (self->screen);
compositor = meta_display_get_compositor (display);
root_pixmap_id = None;
if (!XGetWindowProperty (meta_display_get_xdisplay (display),
meta_screen_get_xroot (self->screen),
compositor->atom_x_root_pixmap,
0, LONG_MAX,
False,
AnyPropertyType,
&type, &format, &nitems, &bytes_after, &data) &&
type != None)
{
/* Got a property. */
if (type == XA_PIXMAP && format == 32 && nitems == 1)
{
/* Was what we expected. */
root_pixmap_id = *(Pixmap *)data;
}
XFree(data);
}
if (root_pixmap_id != None)
{
CoglHandle texture;
meta_error_trap_push (display);
texture = cogl_texture_pixmap_x11_new (root_pixmap_id, FALSE);
meta_error_trap_pop (display);
if (texture != COGL_INVALID_HANDLE)
{
set_texture (self, texture);
cogl_handle_unref (texture);
self->have_pixmap = True;
return;
}
}
self->have_pixmap = False;
set_texture_to_stage_color (self);
}
/**
* meta_background_actor_set_visible_region:
* @self: a #MetaBackgroundActor
* @visible_region: (allow-none): the area of the actor (in allocate-relative
* coordinates) that is visible.
*
* Sets the area of the background that is unobscured by overlapping windows.
* This is used to optimize and only paint the visible portions.
*/
void
meta_background_actor_set_visible_region (MetaBackgroundActor *self,
cairo_region_t *visible_region)
{
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
if (self->visible_region)
{
cairo_region_destroy (self->visible_region);
self->visible_region = NULL;
}
if (visible_region)
{
cairo_rectangle_int_t screen_rect = { 0 };
meta_screen_get_size (self->screen, &screen_rect.width, &screen_rect.height);
/* Doing the intersection here is probably unnecessary - MetaWindowGroup
* should never compute a visible area that's larger than the root screen!
* but it's not that expensive and adds some extra robustness.
*/
self->visible_region = cairo_region_create_rectangle (&screen_rect);
cairo_region_intersect (self->visible_region, visible_region);
}
}
/**
* meta_background_actor_screen_size_changed:
* @self: a #MetaBackgroundActor
*
* Called by the compositor when the size of the #MetaScreen changes
*/
void
meta_background_actor_screen_size_changed (MetaBackgroundActor *self)
{
update_wrap_mode (self);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
}

View File

@@ -0,0 +1,58 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* meta-background-actor.h: Actor for painting the root window background
*
* 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
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_BACKGROUND_ACTOR_H
#define META_BACKGROUND_ACTOR_H
#include <clutter/clutter.h>
#include "screen.h"
/**
* MetaBackgroundActor:
*
* 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_ACTOR (meta_background_actor_get_type ())
#define META_BACKGROUND_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKGROUND_ACTOR, MetaBackgroundActor))
#define META_BACKGROUND_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_BACKGROUND_ACTOR, MetaBackgroundActorClass))
#define META_IS_BACKGROUND_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_BACKGROUND_ACTOR))
#define META_IS_BACKGROUND_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_BACKGROUND_ACTOR))
#define META_BACKGROUND_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_BACKGROUND_ACTOR, MetaBackgroundActorClass))
typedef struct _MetaBackgroundActor MetaBackgroundActor;
typedef struct _MetaBackgroundActorClass MetaBackgroundActorClass;
typedef struct _MetaBackgroundActorPrivate MetaBackgroundActorPrivate;
GType meta_background_actor_get_type (void);
ClutterActor *meta_background_actor_new (MetaScreen *screen);
void meta_background_actor_update (MetaBackgroundActor *actor);
void meta_background_actor_set_visible_region (MetaBackgroundActor *self,
cairo_region_t *visible_region);
void meta_background_actor_screen_size_changed (MetaBackgroundActor *self);
#endif /* META_BACKGROUND_ACTOR_H */

View File

@@ -351,6 +351,14 @@ meta_plugin_get_window_group (MetaPlugin *plugin)
return meta_get_window_group_for_screen (priv->screen);
}
ClutterActor *
meta_plugin_get_background_actor (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return meta_get_background_actor_for_screen (priv->screen);
}
/**
* _meta_plugin_effect_started:
* @plugin: the plugin

View File

@@ -0,0 +1,67 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* MetaShadowFactory:
*
* Create and cache shadow textures for arbitrary window shapes
*
* Copyright (C) 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
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef __META_SHADOW_FACTORY_PRIVATE_H__
#define __META_SHADOW_FACTORY_PRIVATE_H__
#include <cairo.h>
#include <clutter/clutter.h>
#include "meta-window-shape.h"
#include "meta-shadow-factory.h"
/**
* MetaShadow:
* #MetaShadow holds a shadow texture along with information about how to
* apply that texture to draw a window texture. (E.g., it knows how big the
* unscaled borders are on each side of the shadow texture.)
*/
typedef struct _MetaShadow MetaShadow;
MetaShadow *meta_shadow_ref (MetaShadow *shadow);
void meta_shadow_unref (MetaShadow *shadow);
CoglHandle meta_shadow_get_texture (MetaShadow *shadow);
void meta_shadow_paint (MetaShadow *shadow,
int window_x,
int window_y,
int window_width,
int window_height,
guint8 opacity,
cairo_region_t *clip);
void meta_shadow_get_bounds (MetaShadow *shadow,
int window_x,
int window_y,
int window_width,
int window_height,
cairo_rectangle_int_t *bounds);
MetaShadowFactory *meta_shadow_factory_new (void);
MetaShadow *meta_shadow_factory_get_shadow (MetaShadowFactory *factory,
MetaWindowShape *shape,
int width,
int height,
const char *class_name,
gboolean focused);
#endif /* __META_SHADOW_FACTORY_PRIVATE_H__ */

View File

@@ -0,0 +1,989 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* MetaShadowFactory:
*
* Create and cache shadow textures for abritrary window shapes
*
* 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
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <config.h>
#include <math.h>
#include <string.h>
#include "cogl-utils.h"
#include "meta-shadow-factory-private.h"
#include "region-utils.h"
/* This file implements blurring the shape of a window to produce a
* shadow texture. The details are discussed below; a quick summary
* of the optimizations we use:
*
* - If the window shape is along the lines of a rounded rectangle -
* a rectangular center portion with stuff at the corners - then
* the blur of this - the shadow - can also be represented as a
* 9-sliced texture and the same texture can be used for different
* size.
*
* - We use the fact that a Gaussian blur is separable to do a
* 2D blur as 1D blur of the rows followed by a 1D blur of the
* columns.
*
* - For better cache efficiency, we blur rows, transpose the image
* in blocks, blur rows again, and then transpose back.
*
* - We approximate the 1D gaussian blur as 3 successive box filters.
*/
typedef struct _MetaShadowCacheKey MetaShadowCacheKey;
typedef struct _MetaShadowClassInfo MetaShadowClassInfo;
struct _MetaShadowCacheKey
{
MetaWindowShape *shape;
int radius;
int top_fade;
};
struct _MetaShadow
{
int ref_count;
MetaShadowFactory *factory;
MetaShadowCacheKey key;
CoglHandle texture;
CoglHandle material;
/* The outer order is the distance the shadow extends outside the window
* shape; the inner border is the unscaled portion inside the window
* shape */
int outer_border_top;
int inner_border_top;
int outer_border_right;
int inner_border_right;
int outer_border_bottom;
int inner_border_bottom;
int outer_border_left;
int inner_border_left;
guint scale_width : 1;
guint scale_height : 1;
};
struct _MetaShadowClassInfo
{
const char *name; /* const so we can reuse for static definitions */
MetaShadowParams focused;
MetaShadowParams unfocused;
};
struct _MetaShadowFactory
{
GObject parent_instance;
/* MetaShadowCacheKey => MetaShadow; the shadows are not referenced
* by the factory, they are simply removed from the table when freed */
GHashTable *shadows;
/* class name => MetaShadowClassInfo */
GHashTable *shadow_classes;
};
struct _MetaShadowFactoryClass
{
GObjectClass parent_class;
};
enum
{
CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
/* The first element in this array also defines the default parameters
* for newly created classes */
MetaShadowClassInfo default_shadow_classes[] = {
{ "normal", { 12, -1, 0, 8, 255 }, { 6, -1, 0, 4, 255 } },
{ "dialog", { 12, -1, 0, 8, 255 }, { 6, -1, 0, 4, 255 } },
{ "modal_dialog", { 12, -1, 0, 8, 255 }, { 6, -1, 0, 4, 255 } },
{ "utility", { 12, -1, 0, 8, 255 }, { 6, -1, 0, 4, 255 } },
{ "border", { 12, -1, 0, 8, 255 }, { 6, -1, 0, 4, 255 } },
{ "menu", { 12, -1, 0, 8, 255 }, { 6, -1, 0, 4, 255 } },
{ "popup-menu", { 6, -1, 0, 4, 255 }, { 6, -1, 0, 4, 255 } },
{ "dropdown-menu", { 6, 25, 0, 4, 255 }, { 6, 100, 0, 4, 255 } },
{ "attached", { 6, 25, 0, 4, 255 }, { 6, 100, 0, 4, 255 } }
};
G_DEFINE_TYPE (MetaShadowFactory, meta_shadow_factory, G_TYPE_OBJECT);
static guint
meta_shadow_cache_key_hash (gconstpointer val)
{
const MetaShadowCacheKey *key = val;
return 59 * key->radius + 67 * key->top_fade + 73 * meta_window_shape_hash (key->shape);
}
static gboolean
meta_shadow_cache_key_equal (gconstpointer a,
gconstpointer b)
{
const MetaShadowCacheKey *key_a = a;
const MetaShadowCacheKey *key_b = b;
return (key_a->radius == key_b->radius && key_a->top_fade == key_b->top_fade &&
meta_window_shape_equal (key_a->shape, key_b->shape));
}
MetaShadow *
meta_shadow_ref (MetaShadow *shadow)
{
shadow->ref_count++;
return shadow;
}
void
meta_shadow_unref (MetaShadow *shadow)
{
shadow->ref_count--;
if (shadow->ref_count == 0)
{
if (shadow->factory)
{
g_hash_table_remove (shadow->factory->shadows,
&shadow->key);
}
meta_window_shape_unref (shadow->key.shape);
cogl_handle_unref (shadow->texture);
cogl_handle_unref (shadow->material);
g_slice_free (MetaShadow, shadow);
}
}
/**
* meta_shadow_paint:
* @window_x: x position of the region to paint a shadow for
* @window_y: y position of the region to paint a shadow for
* @window_width: actual width of the region to paint a shadow for
* @window_height: actual height of the region to paint a shadow for
* @clip: (allow-none): if non-%NULL specifies the visible portion
* of the shadow. Drawing won't be strictly clipped to this region
* but it will be used to optimize what is drawn.
*
* Paints the shadow at the given position, for the specified actual
* size of the region. (Since a #MetaShadow can be shared between
* different sizes with the same extracted #MetaWindowShape the
* size needs to be passed in here.)
*/
void
meta_shadow_paint (MetaShadow *shadow,
int window_x,
int window_y,
int window_width,
int window_height,
guint8 opacity,
cairo_region_t *clip)
{
float texture_width = cogl_texture_get_width (shadow->texture);
float texture_height = cogl_texture_get_height (shadow->texture);
int i, j;
float src_x[4];
float src_y[4];
int dest_x[4];
int dest_y[4];
int n_x, n_y;
cogl_material_set_color4ub (shadow->material,
opacity, opacity, opacity, opacity);
cogl_set_source (shadow->material);
if (shadow->scale_width)
{
n_x = 3;
src_x[0] = 0.0;
src_x[1] = (shadow->inner_border_left + shadow->outer_border_left) / texture_width;
src_x[2] = (texture_width - (shadow->inner_border_right + shadow->outer_border_right)) / texture_width;
src_x[3] = 1.0;
dest_x[0] = window_x - shadow->outer_border_left;
dest_x[1] = window_x + shadow->inner_border_left;
dest_x[2] = window_x + window_width - shadow->inner_border_right;
dest_x[3] = window_x + window_width + shadow->outer_border_right;
}
else
{
n_x = 1;
src_x[0] = 0.0;
src_x[1] = 1.0;
dest_x[0] = window_x - shadow->outer_border_left;
dest_x[1] = window_x + window_width + shadow->outer_border_right;
}
if (shadow->scale_height)
{
n_y = 3;
src_y[0] = 0.0;
src_y[1] = (shadow->inner_border_top + shadow->outer_border_top) / texture_height;
src_y[2] = (texture_height - (shadow->inner_border_bottom + shadow->outer_border_bottom)) / texture_height;
src_y[3] = 1.0;
dest_y[0] = window_y - shadow->outer_border_top;
dest_y[1] = window_y + shadow->inner_border_top;
dest_y[2] = window_y + window_height - shadow->inner_border_bottom;
dest_y[3] = window_y + window_height + shadow->outer_border_bottom;
}
else
{
n_y = 1;
src_y[0] = 0.0;
src_y[1] = 1.0;
dest_y[0] = window_y - shadow->outer_border_top;
dest_y[1] = window_y + window_height + shadow->outer_border_bottom;
}
for (j = 0; j < n_y; j++)
{
cairo_rectangle_int_t dest_rect;
dest_rect.y = dest_y[j];
dest_rect.height = dest_y[j + 1] - dest_y[j];
for (i = 0; i < n_x; i++)
{
cairo_region_overlap_t overlap;
dest_rect.x = dest_x[i];
dest_rect.width = dest_x[i + 1] - dest_x[i];
if (clip)
overlap = cairo_region_contains_rectangle (clip, &dest_rect);
else
overlap = CAIRO_REGION_OVERLAP_PART;
if (overlap != CAIRO_REGION_OVERLAP_OUT)
cogl_rectangle_with_texture_coords (dest_x[i], dest_y[j],
dest_x[i + 1], dest_y[j + 1],
src_x[i], src_y[j],
src_x[i + 1], src_y[j + 1]);
}
}
}
/**
* meta_shadow_get_bounds:
* @shadow: a #MetaShadow
* @window_x: x position of the region to paint a shadow for
* @window_y: y position of the region to paint a shadow for
* @window_width: actual width of the region to paint a shadow for
* @window_height: actual height of the region to paint a shadow for
*
* Computes the bounds of the pixels that will be affected by
* meta_shadow_paints()
*/
void
meta_shadow_get_bounds (MetaShadow *shadow,
int window_x,
int window_y,
int window_width,
int window_height,
cairo_rectangle_int_t *bounds)
{
bounds->x = window_x - shadow->outer_border_left;
bounds->y = window_x - shadow->outer_border_top;
bounds->width = window_width + shadow->outer_border_left + shadow->outer_border_right;
bounds->height = window_height + shadow->outer_border_top + shadow->outer_border_bottom;
}
static void
meta_shadow_class_info_free (MetaShadowClassInfo *class_info)
{
g_free ((char *)class_info->name);
g_slice_free (MetaShadowClassInfo, class_info);
}
static void
meta_shadow_factory_init (MetaShadowFactory *factory)
{
guint i;
factory->shadows = g_hash_table_new (meta_shadow_cache_key_hash,
meta_shadow_cache_key_equal);
factory->shadow_classes = g_hash_table_new_full (g_str_hash,
g_str_equal,
NULL,
(GDestroyNotify)meta_shadow_class_info_free);
for (i = 0; i < G_N_ELEMENTS (default_shadow_classes); i++)
{
MetaShadowClassInfo *class_info = g_slice_new (MetaShadowClassInfo);
*class_info = default_shadow_classes[i];
class_info->name = g_strdup (class_info->name);
g_hash_table_insert (factory->shadow_classes,
(char *)class_info->name, class_info);
}
}
static void
meta_shadow_factory_finalize (GObject *object)
{
MetaShadowFactory *factory = META_SHADOW_FACTORY (object);
GHashTableIter iter;
gpointer key, value;
/* Detach from the shadows in the table so we won't try to
* remove them when they're freed. */
g_hash_table_iter_init (&iter, factory->shadows);
while (g_hash_table_iter_next (&iter, &key, &value))
{
MetaShadow *shadow = key;
shadow->factory = NULL;
}
g_hash_table_destroy (factory->shadows);
g_hash_table_destroy (factory->shadow_classes);
G_OBJECT_CLASS (meta_shadow_factory_parent_class)->finalize (object);
}
static void
meta_shadow_factory_class_init (MetaShadowFactoryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_shadow_factory_finalize;
signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
MetaShadowFactory *
meta_shadow_factory_new (void)
{
return g_object_new (META_TYPE_SHADOW_FACTORY, NULL);
}
/**
* meta_shadow_factory_get_default:
*
* Return value: (transfer none): the global singleton shadow factory
*/
MetaShadowFactory *
meta_shadow_factory_get_default (void)
{
static MetaShadowFactory *factory;
if (factory == NULL)
factory = meta_shadow_factory_new ();
return factory;
}
/* We emulate a 1D Gaussian blur by using 3 consecutive box blurs;
* this produces a result that's within 3% of the original and can be
* implemented much faster for large filter sizes because of the
* efficiency of implementation of a box blur. Idea and formula
* for choosing the box blur size come from:
*
* http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement
*
* The 2D blur is then done by blurring the rows, flipping the
* image and blurring the columns. (This is possible because the
* Gaussian kernel is separable - it's the product of a horizontal
* blur and a vertical blur.)
*/
static int
get_box_filter_size (int radius)
{
return (int)(0.5 + radius * (0.75 * sqrt(2*M_PI)));
}
/* The "spread" of the filter is the number of pixels from an original
* pixel that it's blurred image extends. (A no-op blur that doesn't
* blur would have a spread of 0.) See comment in blur_rows() for why the
* odd and even cases are different
*/
static int
get_shadow_spread (int radius)
{
int d = get_box_filter_size (radius);
if (d % 2 == 1)
return 3 * (d / 2);
else
return 3 * (d / 2) - 1;
}
/* This applies a single box blur pass to a horizontal range of pixels;
* since the box blur has the same weight for all pixels, we can
* implement an efficient sliding window algorithm where we add
* in pixels coming into the window from the right and remove
* them when they leave the windw to the left.
*
* d is the filter width; for even d shift indicates how the blurred
* result is aligned with the original - does ' x ' go to ' yy' (shift=1)
* or 'yy ' (shift=-1)
*/
static void
blur_xspan (guchar *row,
guchar *tmp_buffer,
int row_width,
int x0,
int x1,
int d,
int shift)
{
int offset;
int sum = 0;
int i;
if (d % 2 == 1)
offset = d / 2;
else
offset = (d - shift) / 2;
/* All the conditionals in here look slow, but the branches will
* be well predicted and there are enough different possibilities
* that trying to write this as a series of unconditional loops
* is hard and not an obvious win. The main slow down here seems
* to be the integer division for pixel; one possible optimization
* would be to accumulate into two 16-bit integer buffers and
* only divide down after all three passes. (SSE parallel implementation
* of the divide step is possible.)
*/
for (i = x0 - d + offset; i < x1 + offset; i++)
{
if (i >= 0 && i < row_width)
sum += row[i];
if (i >= x0 + offset)
{
if (i >= d)
sum -= row[i - d];
tmp_buffer[i - offset] = (sum + d / 2) / d;
}
}
memcpy(row + x0, tmp_buffer + x0, x1 - x0);
}
static void
blur_rows (cairo_region_t *convolve_region,
int x_offset,
int y_offset,
guchar *buffer,
int buffer_width,
int buffer_height,
int d)
{
int i, j;
int n_rectangles;
guchar *tmp_buffer;
tmp_buffer = g_malloc (buffer_width);
n_rectangles = cairo_region_num_rectangles (convolve_region);
for (i = 0; i < n_rectangles; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (convolve_region, i, &rect);
for (j = y_offset + rect.y; j < y_offset + rect.y + rect.height; j++)
{
guchar *row = buffer + j * buffer_width;
int x0 = x_offset + rect.x;
int x1 = x0 + rect.width;
/* We want to produce a symmetric blur that spreads a pixel
* equally far to the left and right. If d is odd that happens
* naturally, but for d even, we approximate by using a blur
* on either side and then a centered blur of size d + 1.
* (techique also from the SVG specification)
*/
if (d % 2 == 1)
{
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 0);
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 0);
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 0);
}
else
{
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 1);
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, -1);
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d + 1, 0);
}
}
}
g_free (tmp_buffer);
}
static void
fade_bytes (guchar *bytes,
int width,
int distance,
int total)
{
guint32 multiplier = (distance * 0x10000 + 0x8000) / total;
int i;
for (i = 0; i < width; i++)
bytes[i] = (bytes[i] * multiplier) >> 16;
}
/* Swaps width and height. Either swaps in-place and returns the original
* buffer or allocates a new buffer, frees the original buffer and returns
* the new buffer.
*/
static guchar *
flip_buffer (guchar *buffer,
int width,
int height)
{
/* Working in blocks increases cache efficiency, compared to reading
* or writing an entire column at once */
#define BLOCK_SIZE 16
if (width == height)
{
int i0, j0;
for (j0 = 0; j0 < height; j0 += BLOCK_SIZE)
for (i0 = 0; i0 <= j0; i0 += BLOCK_SIZE)
{
int max_j = MIN(j0 + BLOCK_SIZE, height);
int max_i = MIN(i0 + BLOCK_SIZE, width);
int i, j;
if (i0 == j0)
{
for (j = j0; j < max_j; j++)
for (i = i0; i < j; i++)
{
guchar tmp = buffer[j * width + i];
buffer[j * width + i] = buffer[i * width + j];
buffer[i * width + j] = tmp;
}
}
else
{
for (j = j0; j < max_j; j++)
for (i = i0; i < max_i; i++)
{
guchar tmp = buffer[j * width + i];
buffer[j * width + i] = buffer[i * width + j];
buffer[i * width + j] = tmp;
}
}
}
return buffer;
}
else
{
guchar *new_buffer = g_malloc (height * width);
int i0, j0;
for (i0 = 0; i0 < width; i0 += BLOCK_SIZE)
for (j0 = 0; j0 < height; j0 += BLOCK_SIZE)
{
int max_j = MIN(j0 + BLOCK_SIZE, height);
int max_i = MIN(i0 + BLOCK_SIZE, width);
int i, j;
for (i = i0; i < max_i; i++)
for (j = j0; j < max_j; j++)
new_buffer[i * height + j] = buffer[j * width + i];
}
g_free (buffer);
return new_buffer;
}
#undef BLOCK_SIZE
}
static void
make_shadow (MetaShadow *shadow,
cairo_region_t *region)
{
int d = get_box_filter_size (shadow->key.radius);
int spread = get_shadow_spread (shadow->key.radius);
cairo_rectangle_int_t extents;
cairo_region_t *row_convolve_region;
cairo_region_t *column_convolve_region;
guchar *buffer;
int buffer_width;
int buffer_height;
int x_offset;
int y_offset;
int n_rectangles, j, k;
cairo_region_get_extents (region, &extents);
/* In the case where top_fade >= 0 and the portion above the top
* edge of the shape will be cropped, it seems like we could create
* a smaller buffer and omit the top portion, but actually, in our
* multi-pass blur algorithm, the blur into the area above the window
* in the first pass will contribute back to the final pixel values
* for the top pixels, so we create a buffer as if we weren't cropping
* and only crop when creating the CoglTexture.
*/
buffer_width = extents.width + 2 * spread;
buffer_height = extents.height + 2 * spread;
/* Round up so we have aligned rows/columns */
buffer_width = (buffer_width + 3) & ~3;
buffer_height = (buffer_height + 3) & ~3;
/* Square buffer allows in-place swaps, which are roughly 70% faster, but we
* don't want to over-allocate too much memory.
*/
if (buffer_height < buffer_width && buffer_height > (3 * buffer_width) / 4)
buffer_height = buffer_width;
if (buffer_width < buffer_height && buffer_width > (3 * buffer_height) / 4)
buffer_width = buffer_height;
buffer = g_malloc0 (buffer_width * buffer_height);
/* Blurring with multiple box-blur passes is fast, but (especially for
* large shadow sizes) we can improve efficiency by restricting the blur
* to the region that actually needs to be blurred.
*/
row_convolve_region = meta_make_border_region (region, spread, spread, FALSE);
column_convolve_region = meta_make_border_region (region, 0, spread, TRUE);
/* Offsets between coordinates of the regions and coordinates in the buffer */
x_offset = spread;
y_offset = spread;
/* Step 1: unblurred image */
n_rectangles = cairo_region_num_rectangles (region);
for (k = 0; k < n_rectangles; k++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, k, &rect);
for (j = y_offset + rect.y; j < y_offset + rect.y + rect.height; j++)
memset (buffer + buffer_width * j + x_offset + rect.x, 255, rect.width);
}
/* Step 2: swap rows and columns */
buffer = flip_buffer (buffer, buffer_width, buffer_height);
/* Step 3: blur rows (really columns) */
blur_rows (column_convolve_region, y_offset, x_offset,
buffer, buffer_height, buffer_width,
d);
/* Step 4: swap rows and columns */
buffer = flip_buffer (buffer, buffer_height, buffer_width);
/* Step 5: blur rows */
blur_rows (row_convolve_region, x_offset, y_offset,
buffer, buffer_width, buffer_height,
d);
/* Step 6: fade out the top, if applicable */
if (shadow->key.top_fade >= 0)
{
for (j = y_offset; j < y_offset + MIN (shadow->key.top_fade, extents.height + shadow->outer_border_bottom); j++)
fade_bytes(buffer + j * buffer_width, buffer_width, j - y_offset, shadow->key.top_fade);
}
/* We offset the passed in pixels to crop off the extra area we allocated at the top
* in the case of top_fade >= 0. We also account for padding at the left for symmetry
* though that doesn't currently occur.
*/
shadow->texture = cogl_texture_new_from_data (shadow->outer_border_left + extents.width + shadow->outer_border_right,
shadow->outer_border_top + extents.height + shadow->outer_border_bottom,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_A_8,
COGL_PIXEL_FORMAT_ANY,
buffer_width,
(buffer +
(y_offset - shadow->outer_border_top) * buffer_width +
(x_offset - shadow->outer_border_left)));
cairo_region_destroy (row_convolve_region);
cairo_region_destroy (column_convolve_region);
g_free (buffer);
shadow->material = meta_create_texture_material (shadow->texture);
}
static MetaShadowParams *
get_shadow_params (MetaShadowFactory *factory,
const char *class_name,
gboolean focused,
gboolean create)
{
MetaShadowClassInfo *class_info = g_hash_table_lookup (factory->shadow_classes,
class_name);
if (class_info == NULL)
{
if (create)
{
class_info = g_slice_new0 (MetaShadowClassInfo);
*class_info = default_shadow_classes[0];
class_info->name = g_strdup (class_info->name);
g_hash_table_insert (factory->shadow_classes,
(char *)class_info->name, class_info);
}
else
{
class_info = &default_shadow_classes[0];
}
}
if (focused)
return &class_info->focused;
else
return &class_info->unfocused;
}
/**
* meta_shadow_factory_get_shadow:
* @factory: a #MetaShadowFactory
* @shape: the size-invariant shape of the window's region
* @width: the actual width of the window's region
* @height: the actual height of the window's region
* @class_name: name of the class of window shadows
* @focused: whether the shadow is for a focused window
*
* Gets the appropriate shadow object for drawing shadows for the
* specified window shape. The region that we are shadowing is specified
* as a combination of a size-invariant extracted shape and the size.
* In some cases, the same shadow object can be shared between sizes;
* in other cases a different shadow object is used for each size.
*
* Return value: (transfer full): a newly referenced #MetaShadow; unref with
* meta_shadow_unref()
*/
MetaShadow *
meta_shadow_factory_get_shadow (MetaShadowFactory *factory,
MetaWindowShape *shape,
int width,
int height,
const char *class_name,
gboolean focused)
{
MetaShadowParams *params;
MetaShadowCacheKey key;
MetaShadow *shadow;
cairo_region_t *region;
int spread;
int shape_border_top, shape_border_right, shape_border_bottom, shape_border_left;
int inner_border_top, inner_border_right, inner_border_bottom, inner_border_left;
int outer_border_top, outer_border_right, outer_border_bottom, outer_border_left;
gboolean scale_width, scale_height;
gboolean cacheable;
int center_width, center_height;
g_return_val_if_fail (META_IS_SHADOW_FACTORY (factory), NULL);
g_return_val_if_fail (shape != NULL, NULL);
/* Using a single shadow texture for different window sizes only works
* when there is a central scaled area that is greater than twice
* the spread of the gaussian blur we are applying to get to the
* shadow image.
* ********* ***********
* /----------\ *###########* *#############*
* | | => **#*********#** => **#***********#**
* | | **#** **#** **#** **#**
* | | **#*********#** **#***********#**
* \----------/ *###########* *#############*
* ********** ************
* Original Blur Stretched Blur
*
* For smaller sizes, we create a separate shadow image for each size;
* since we assume that there will be little reuse, we don't try to
* cache such images but just recreate them. (Since the current cache
* policy is to only keep around referenced shadows, there wouldn't
* be any harm in caching them, it would just make the book-keeping
* a bit tricker.)
*
* In the case where we are fading a the top, that also has to fit
* within the top unscaled border.
*/
params = get_shadow_params (factory, class_name, focused, FALSE);
spread = get_shadow_spread (params->radius);
meta_window_shape_get_borders (shape,
&shape_border_top,
&shape_border_right,
&shape_border_bottom,
&shape_border_left);
inner_border_top = MAX (shape_border_top + spread, params->top_fade);
outer_border_top = params->top_fade >= 0 ? 0 : spread;
inner_border_right = shape_border_right + spread;
outer_border_right = spread;
inner_border_bottom = shape_border_bottom + spread;
outer_border_bottom = spread;
inner_border_left = shape_border_left + spread;
outer_border_left = spread;
scale_width = inner_border_left + inner_border_right <= width;
scale_height = inner_border_top + inner_border_bottom <= height;
cacheable = scale_width && scale_height;
if (cacheable)
{
key.shape = shape;
key.radius = params->radius;
key.top_fade = params->top_fade;
shadow = g_hash_table_lookup (factory->shadows, &key);
if (shadow)
return meta_shadow_ref (shadow);
}
shadow = g_slice_new0 (MetaShadow);
shadow->ref_count = 1;
shadow->factory = factory;
shadow->key.shape = meta_window_shape_ref (shape);
shadow->key.radius = params->radius;
shadow->key.top_fade = params->top_fade;
shadow->outer_border_top = outer_border_top;
shadow->inner_border_top = inner_border_top;
shadow->outer_border_right = outer_border_right;
shadow->inner_border_right = inner_border_right;
shadow->outer_border_bottom = outer_border_bottom;
shadow->inner_border_bottom = inner_border_bottom;
shadow->outer_border_left = outer_border_left;
shadow->inner_border_left = inner_border_left;
shadow->scale_width = scale_width;
if (scale_width)
center_width = inner_border_left + inner_border_right - (shape_border_left + shape_border_right);
else
center_width = width - (shape_border_left + shape_border_right);
shadow->scale_height = scale_height;
if (scale_height)
center_height = inner_border_top + inner_border_bottom - (shape_border_top + shape_border_bottom);
else
center_height = height - (shape_border_top + shape_border_bottom);
g_assert (center_width >= 0 && center_height >= 0);
region = meta_window_shape_to_region (shape, center_width, center_height);
make_shadow (shadow, region);
cairo_region_destroy (region);
if (cacheable)
g_hash_table_insert (factory->shadows, &shadow->key, shadow);
return shadow;
}
/**
* meta_shadow_factory_set_params:
* @factory: a #MetaShadowFactory
* @class_name: name of the class of shadow to set the params for.
* the default shadow classes are the names of the different
* theme frame types (normal, dialog, modal_dialog, utility,
* border, menu, attached) and in addition, popup-menu
* and dropdown-menu.
* @focused: whether the shadow is for a focused window
* @params: new parameter values
*
* Updates the shadow parameters for a particular class of shadows
* for either the focused or unfocused state. If the class name
* does not name an existing class, a new class will be created
* (the other focus state for that class will have default values
* assigned to it.)
*/
void
meta_shadow_factory_set_params (MetaShadowFactory *factory,
const char *class_name,
gboolean focused,
MetaShadowParams *params)
{
MetaShadowParams *stored_params;
g_return_if_fail (META_IS_SHADOW_FACTORY (factory));
g_return_if_fail (class_name != NULL);
g_return_if_fail (params != NULL);
g_return_if_fail (params->radius >= 0);
stored_params = get_shadow_params (factory, class_name, focused, TRUE);
*stored_params = *params;
g_signal_emit (factory, signals[CHANGED], 0);
}
/**
* meta_shadow_factory_get_params:
* @factory: a #MetaShadowFactory
* @class_name: name of the class of shadow to get the params for
* @focused: whether the shadow is for a focused window
* @params: (out caller-allocates): location to store the current parameter values
*
* Gets the shadow parameters for a particular class of shadows
* for either the focused or unfocused state. If the class name
* does not name an existing class, default values will be returned
* without printing an error.
*/
void
meta_shadow_factory_get_params (MetaShadowFactory *factory,
const char *class_name,
gboolean focused,
MetaShadowParams *params)
{
MetaShadowParams *stored_params;
g_return_if_fail (META_IS_SHADOW_FACTORY (factory));
g_return_if_fail (class_name != NULL);
stored_params = get_shadow_params (factory, class_name, focused, FALSE);
if (params)
*params = *stored_params;
}

View File

@@ -187,8 +187,10 @@ meta_shaped_texture_dirty_mask (MetaShapedTexture *stex)
cogl_texture_get_gl_texture (priv->mask_texture,
&mask_gl_tex, &mask_gl_target);
#ifdef GL_TEXTURE_RECTANGLE_ARB
if (mask_gl_target == GL_TEXTURE_RECTANGLE_ARB)
glDeleteTextures (1, &mask_gl_tex);
#endif
cogl_handle_unref (priv->mask_texture);
priv->mask_texture = COGL_INVALID_HANDLE;
@@ -253,6 +255,7 @@ meta_shaped_texture_ensure_mask (MetaShapedTexture *stex)
cogl_texture_get_gl_texture (paint_tex, NULL, &paint_gl_target);
#ifdef GL_TEXTURE_RECTANGLE_ARB
if (paint_gl_target == GL_TEXTURE_RECTANGLE_ARB)
{
GLuint tex;
@@ -275,6 +278,7 @@ meta_shaped_texture_ensure_mask (MetaShapedTexture *stex)
COGL_PIXEL_FORMAT_A_8);
}
else
#endif /* GL_TEXTURE_RECTANGLE_ARB */
priv->mask_texture = cogl_texture_new_from_data (tex_width, tex_height,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_A_8,

View File

@@ -97,6 +97,7 @@ meta_texture_tower_free (MetaTextureTower *tower)
g_slice_free (MetaTextureTower, tower);
}
#ifdef GL_TEXTURE_RECTANGLE_ARB
static gboolean
texture_is_rectangle (CoglHandle texture)
{
@@ -106,10 +107,12 @@ texture_is_rectangle (CoglHandle texture)
cogl_texture_get_gl_texture (texture, &gl_tex, &gl_target);
return gl_target == GL_TEXTURE_RECTANGLE_ARB;
}
#endif /* GL_TEXTURE_RECTANGLE_ARB */
static void
free_texture (CoglHandle texture)
{
#ifdef GL_TEXTURE_RECTANGLE_ARB
GLuint gl_tex;
GLenum gl_target;
@@ -117,6 +120,7 @@ free_texture (CoglHandle texture)
if (gl_target == GL_TEXTURE_RECTANGLE_ARB)
glDeleteTextures (1, &gl_tex);
#endif /* GL_TEXTURE_RECTANGLE_ARB */
cogl_handle_unref (texture);
}
@@ -362,11 +366,13 @@ get_paint_level (int width, int height)
return (int)(0.5 + lambda);
}
#ifdef GL_TEXTURE_RECTANGLE_ARB
static gboolean
is_power_of_two (int x)
{
return (x & (x - 1)) == 0;
}
#endif /* GL_TEXTURE_RECTANGLE_ARB */
static void
texture_tower_create_texture (MetaTextureTower *tower,
@@ -374,6 +380,7 @@ texture_tower_create_texture (MetaTextureTower *tower,
int width,
int height)
{
#ifdef GL_TEXTURE_RECTANGLE_ARB
if ((!is_power_of_two (width) || !is_power_of_two (height)) &&
texture_is_rectangle (tower->textures[level - 1]))
{
@@ -396,6 +403,7 @@ texture_tower_create_texture (MetaTextureTower *tower,
TEXTURE_FORMAT);
}
else
#endif /* GL_TEXTURE_RECTANGLE_ARB */
{
tower->textures[level] = cogl_texture_new_with_size (width, height,
COGL_TEXTURE_NO_AUTO_MIPMAP,

View File

@@ -28,6 +28,8 @@ void meta_window_actor_process_damage (MetaWindowActor *self,
XDamageNotifyEvent *event);
void meta_window_actor_pre_paint (MetaWindowActor *self);
void meta_window_actor_invalidate_shadow (MetaWindowActor *self);
gboolean meta_window_actor_effect_in_progress (MetaWindowActor *self);
void meta_window_actor_sync_actor_position (MetaWindowActor *self);
void meta_window_actor_sync_visibility (MetaWindowActor *self);

View File

@@ -1,5 +1,7 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include <config.h>
#define _ISOC99_SOURCE /* for roundf */
#include <math.h>
@@ -9,6 +11,7 @@
#include <X11/extensions/Xrender.h>
#include <clutter/x11/clutter-x11.h>
#include <gdk/gdk.h> /* for gdk_rectangle_union() */
#include "display.h"
#include "errors.h"
@@ -17,10 +20,17 @@
#include "xprops.h"
#include "compositor-private.h"
#include "meta-shadow-factory-private.h"
#include "meta-shaped-texture.h"
#include "meta-window-actor-private.h"
#include "shadow.h"
#include "tidy/tidy-texture-frame.h"
enum {
SIZE_CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = {0};
struct _MetaWindowActorPrivate
{
@@ -31,12 +41,27 @@ struct _MetaWindowActorPrivate
MetaScreen *screen;
ClutterActor *actor;
ClutterActor *shadow;
/* MetaShadowFactory only caches shadows that are actually in use;
* to avoid unnecessary recomputation we do two things: 1) we store
* both a focused and unfocused shadow for the window. If the window
* doesn't have different focused and unfocused shadow parameters,
* these will be the same. 2) when the shadow potentially changes we
* don't immediately unreference the old shadow, we just flag it as
* dirty and recompute it when we next need it (recompute_focused_shadow,
* recompute_unfocused_shadow.) Because of our extraction of
* size-invariant window shape, we'll often find that the new shadow
* is the same as the old shadow.
*/
MetaShadow *focused_shadow;
MetaShadow *unfocused_shadow;
Pixmap back_pixmap;
Damage damage;
guint8 opacity;
guint8 shadow_opacity;
gchar * desc;
@@ -45,9 +70,16 @@ struct _MetaWindowActorPrivate
/* A rectangular region with the unshaped extends of the window
* texture */
cairo_region_t *bounding_region;
/* The region we should clip to when painting the shadow */
cairo_region_t *shadow_clip;
/* Extracted size-invariant shape used for shadows */
MetaWindowShape *shadow_shape;
gint freeze_count;
char * shadow_class;
/*
* These need to be counters rather than flags, since more plugins
* can implement same effect; the practicality of stacking effects
@@ -70,7 +102,9 @@ struct _MetaWindowActorPrivate
guint received_damage : 1;
guint needs_pixmap : 1;
guint needs_reshape : 1;
guint needs_reshape : 1;
guint recompute_focused_shadow : 1;
guint recompute_unfocused_shadow : 1;
guint size_changed : 1;
guint needs_destroy : 1;
@@ -87,8 +121,13 @@ enum
PROP_X_WINDOW,
PROP_X_WINDOW_ATTRIBUTES,
PROP_NO_SHADOW,
PROP_SHADOW_CLASS
};
#define DEFAULT_SHADOW_RADIUS 12
#define DEFAULT_SHADOW_X_OFFSET 0
#define DEFAULT_SHADOW_Y_OFFSET 8
static void meta_window_actor_dispose (GObject *object);
static void meta_window_actor_finalize (GObject *object);
static void meta_window_actor_constructed (GObject *object);
@@ -101,11 +140,18 @@ static void meta_window_actor_get_property (GObject *object,
GValue *value,
GParamSpec *pspec);
static void meta_window_actor_paint (ClutterActor *actor);
#if CLUTTER_CHECK_VERSION(1, 5, 2)
static gboolean meta_window_actor_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume);
#endif
static void meta_window_actor_detach (MetaWindowActor *self);
static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
static void meta_window_actor_clear_shape_region (MetaWindowActor *self);
static void meta_window_actor_clear_bounding_region (MetaWindowActor *self);
static void meta_window_actor_clear_shadow_clip (MetaWindowActor *self);
static gboolean is_shaped (MetaDisplay *display,
Window xwindow);
@@ -161,6 +207,7 @@ static void
meta_window_actor_class_init (MetaWindowActorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (MetaWindowActorPrivate));
@@ -171,6 +218,11 @@ meta_window_actor_class_init (MetaWindowActorClass *klass)
object_class->get_property = meta_window_actor_get_property;
object_class->constructed = meta_window_actor_constructed;
actor_class->paint = meta_window_actor_paint;
#if CLUTTER_CHECK_VERSION(1, 5, 2)
actor_class->get_paint_volume = meta_window_actor_get_paint_volume;
#endif
pspec = g_param_spec_object ("meta-window",
"MetaWindow",
"The displayed MetaWindow",
@@ -216,11 +268,29 @@ meta_window_actor_class_init (MetaWindowActorClass *klass)
"No shadow",
"Do not add shaddow to this window",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_NO_SHADOW,
pspec);
pspec = g_param_spec_string ("shadow-class",
"Name of the shadow class for this window.",
"NULL means to use the default shadow class for this window type",
NULL,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_SHADOW_CLASS,
pspec);
signals[SIZE_CHANGED] =
g_signal_new ("size-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
@@ -232,6 +302,7 @@ meta_window_actor_init (MetaWindowActor *self)
META_TYPE_WINDOW_ACTOR,
MetaWindowActorPrivate);
priv->opacity = 0xff;
priv->shadow_class = NULL;
}
static void
@@ -246,7 +317,6 @@ window_decorated_notify (MetaWindow *mw,
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
Window new_xwindow;
MetaCompScreen *info;
XWindowAttributes attrs;
/*
@@ -262,8 +332,6 @@ window_decorated_notify (MetaWindow *mw,
meta_window_actor_detach (self);
info = meta_screen_get_compositor_data (screen);
/*
* First of all, clean up any resources we are currently using and will
* be replacing.
@@ -291,18 +359,6 @@ window_decorated_notify (MetaWindow *mw,
g_object_set (self, "x-window-attributes", &attrs, NULL);
if (priv->shadow)
{
ClutterActor *p = clutter_actor_get_parent (priv->shadow);
if (CLUTTER_IS_CONTAINER (p))
clutter_container_remove_actor (CLUTTER_CONTAINER (p), priv->shadow);
else
clutter_actor_unparent (priv->shadow);
priv->shadow = NULL;
}
/*
* Recreate the contents.
*/
@@ -319,9 +375,6 @@ meta_window_actor_constructed (GObject *object)
Window xwindow = priv->xwindow;
Display *xdisplay = meta_display_get_xdisplay (display);
XRenderPictFormat *format;
MetaCompositor *compositor;
compositor = meta_display_get_compositor (display);
#ifdef HAVE_SHAPE
/* Listen for ShapeNotify events on the window */
@@ -344,13 +397,6 @@ meta_window_actor_constructed (GObject *object)
meta_window_actor_update_opacity (self);
if (meta_window_actor_has_shadow (self))
{
priv->shadow = meta_create_shadow_frame (compositor);
clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->shadow);
}
if (!priv->actor)
{
priv->actor = meta_shaped_texture_new ();
@@ -406,6 +452,31 @@ meta_window_actor_dispose (GObject *object)
meta_window_actor_clear_shape_region (self);
meta_window_actor_clear_bounding_region (self);
meta_window_actor_clear_shadow_clip (self);
if (priv->shadow_class != NULL)
{
g_free (priv->shadow_class);
priv->shadow_class = NULL;
}
if (priv->focused_shadow != NULL)
{
meta_shadow_unref (priv->focused_shadow);
priv->focused_shadow = NULL;
}
if (priv->unfocused_shadow != NULL)
{
meta_shadow_unref (priv->unfocused_shadow);
priv->unfocused_shadow = NULL;
}
if (priv->shadow_shape != NULL)
{
meta_window_shape_unref (priv->shadow_shape);
priv->shadow_shape = NULL;
}
if (priv->damage != None)
{
@@ -463,36 +534,27 @@ meta_window_actor_set_property (GObject *object,
break;
case PROP_NO_SHADOW:
{
gboolean oldv = priv->no_shadow ? TRUE : FALSE;
gboolean newv = g_value_get_boolean (value);
if (oldv == newv)
if (newv == priv->no_shadow)
return;
priv->no_shadow = newv;
if (newv && priv->shadow)
{
clutter_container_remove_actor (CLUTTER_CONTAINER (object),
priv->shadow);
priv->shadow = NULL;
}
else if (!newv && !priv->shadow && meta_window_actor_has_shadow (self))
{
gfloat w, h;
MetaDisplay *display = meta_screen_get_display (priv->screen);
MetaCompositor *compositor;
meta_window_actor_invalidate_shadow (self);
}
break;
case PROP_SHADOW_CLASS:
{
const char *newv = g_value_get_string (value);
compositor = meta_display_get_compositor (display);
if (g_strcmp0 (newv, priv->shadow_class) == 0)
return;
clutter_actor_get_size (CLUTTER_ACTOR (self), &w, &h);
g_free (priv->shadow_class);
priv->shadow_class = g_strdup (newv);
priv->shadow = meta_create_shadow_frame (compositor);
clutter_actor_set_size (priv->shadow, w, h);
clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->shadow);
}
meta_window_actor_invalidate_shadow (self);
}
break;
default:
@@ -526,12 +588,166 @@ meta_window_actor_get_property (GObject *object,
case PROP_NO_SHADOW:
g_value_set_boolean (value, priv->no_shadow);
break;
case PROP_SHADOW_CLASS:
g_value_set_string (value, priv->shadow_class);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static const char *
meta_window_actor_get_shadow_class (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->shadow_class != NULL)
return priv->shadow_class;
else
{
MetaWindowType window_type = meta_window_get_window_type (priv->window);
switch (window_type)
{
case META_WINDOW_DROPDOWN_MENU:
return "dropdown-menu";
case META_WINDOW_POPUP_MENU:
return "popup-menu";
default:
{
MetaFrameType frame_type = meta_window_get_frame_type (priv->window);
return meta_frame_type_to_string (frame_type);
}
}
}
}
static void
meta_window_actor_get_shadow_params (MetaWindowActor *self,
gboolean appears_focused,
MetaShadowParams *params)
{
const char *shadow_class = meta_window_actor_get_shadow_class (self);
meta_shadow_factory_get_params (meta_shadow_factory_get_default (),
shadow_class, appears_focused,
params);
}
static void
meta_window_actor_get_shape_bounds (MetaWindowActor *self,
cairo_rectangle_int_t *bounds)
{
MetaWindowActorPrivate *priv = self->priv;
/* We need to be defensive here because there are corner cases
* where getting the shape fails on a window being destroyed
* and similar.
*/
if (priv->shaped && priv->shape_region)
cairo_region_get_extents (priv->shape_region, bounds);
else if (priv->bounding_region)
cairo_region_get_extents (priv->bounding_region, bounds);
else
bounds->x = bounds->y = bounds->width = bounds->height = 0;
}
#if CLUTTER_CHECK_VERSION(1, 5, 2)
static void
meta_window_actor_get_shadow_bounds (MetaWindowActor *self,
gboolean appears_focused,
cairo_rectangle_int_t *bounds)
{
MetaWindowActorPrivate *priv = self->priv;
MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
cairo_rectangle_int_t shape_bounds;
MetaShadowParams params;
meta_window_actor_get_shape_bounds (self, &shape_bounds);
meta_window_actor_get_shadow_params (self, appears_focused, &params);
meta_shadow_get_bounds (shadow,
params.x_offset + shape_bounds.x,
params.y_offset + shape_bounds.y,
shape_bounds.width,
shape_bounds.height,
bounds);
}
#endif
static void
meta_window_actor_paint (ClutterActor *actor)
{
MetaWindowActor *self = META_WINDOW_ACTOR (actor);
MetaWindowActorPrivate *priv = self->priv;
gboolean appears_focused = meta_window_appears_focused (priv->window);
MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
if (shadow != NULL)
{
MetaShadowParams params;
cairo_rectangle_int_t shape_bounds;
meta_window_actor_get_shape_bounds (self, &shape_bounds);
meta_window_actor_get_shadow_params (self, appears_focused, &params);
meta_shadow_paint (shadow,
params.x_offset + shape_bounds.x,
params.y_offset + shape_bounds.y,
shape_bounds.width,
shape_bounds.height,
(clutter_actor_get_paint_opacity (actor) * params.opacity) / 255,
priv->shadow_clip);
}
CLUTTER_ACTOR_CLASS (meta_window_actor_parent_class)->paint (actor);
}
#if CLUTTER_CHECK_VERSION(1, 5, 2)
static gboolean
meta_window_actor_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
MetaWindowActor *self = META_WINDOW_ACTOR (actor);
MetaWindowActorPrivate *priv = self->priv;
cairo_rectangle_int_t bounds;
gboolean appears_focused = meta_window_appears_focused (priv->window);
ClutterVertex origin;
/* The paint volume is computed before paint functions are called
* so our bounds might not be updated yet. Force an update. */
meta_window_actor_pre_paint (self);
meta_window_actor_get_shape_bounds (self, &bounds);
if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow)
{
cairo_rectangle_int_t shadow_bounds;
/* We could compute an full clip region as we do for the window
* texture, but the shadow is relatively cheap to draw, and
* a little more complex to clip, so we just catch the case where
* the shadow is completely obscured and doesn't need to be drawn
* at all.
*/
meta_window_actor_get_shadow_bounds (self, appears_focused, &shadow_bounds);
gdk_rectangle_union (&bounds, &shadow_bounds, &bounds);
}
origin.x = bounds.x;
origin.y = bounds.y;
origin.z = 0.0f;
clutter_paint_volume_set_origin (volume, &origin);
clutter_paint_volume_set_width (volume, bounds.width);
clutter_paint_volume_set_height (volume, bounds.height);
return TRUE;
}
#endif /* CLUTTER_CHECK_VERSION */
static gboolean
is_shaped (MetaDisplay *display, Window xwindow)
{
@@ -560,10 +776,16 @@ meta_window_actor_has_shadow (MetaWindowActor *self)
if (priv->no_shadow)
return FALSE;
/* Leaving out shadows for maximized and fullscreen windows is an effeciency
* win and also prevents the unsightly effect of the shadow of maximized
* window appearing on an adjacent window */
if ((meta_window_get_maximized (priv->window) == (META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL)) ||
meta_window_is_fullscreen (priv->window))
return FALSE;
/*
* Always put a shadow around windows with a frame - This should override
* the restriction about not putting a shadow around shaped windows
* as the frame might be the reason the window is shaped
* the restriction about not putting a shadow around ARGB windows.
*/
if (priv->window)
{
@@ -576,7 +798,8 @@ meta_window_actor_has_shadow (MetaWindowActor *self)
}
/*
* Do not add shadows to ARGB windows (since they are probably transparent)
* Do not add shadows to ARGB windows; eventually we should generate a
* shadow from the input shape for such windows.
*/
if (priv->argb32 || priv->opacity != 0xff)
{
@@ -585,19 +808,8 @@ meta_window_actor_has_shadow (MetaWindowActor *self)
return FALSE;
}
/*
* Never put a shadow around shaped windows
*/
if (priv->shaped)
{
meta_verbose ("Window 0x%x has no shadow as it is shaped\n",
(guint)priv->xwindow);
return FALSE;
}
/*
* Add shadows to override redirect windows (e.g., Gtk menus).
* This must have lower priority than window shape test.
*/
if (priv->attrs.override_redirect)
{
@@ -681,6 +893,19 @@ meta_window_actor_get_texture (MetaWindowActor *self)
return self->priv->actor;
}
/**
* meta_window_actor_is_destroyed:
*
* Gets whether the X window that the actor was displaying has been destroyed
*
* Return value: %TRUE when the window is destroyed, otherwise %FALSE
*/
gboolean
meta_window_actor_is_destroyed (MetaWindowActor *self)
{
return self->priv->disposed;
}
gboolean
meta_window_actor_is_override_redirect (MetaWindowActor *self)
{
@@ -1358,6 +1583,18 @@ meta_window_actor_clear_bounding_region (MetaWindowActor *self)
}
}
static void
meta_window_actor_clear_shadow_clip (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->shadow_clip)
{
cairo_region_destroy (priv->shadow_clip);
priv->shadow_clip = NULL;
}
}
static void
meta_window_actor_update_bounding_region (MetaWindowActor *self,
int width,
@@ -1366,9 +1603,28 @@ meta_window_actor_update_bounding_region (MetaWindowActor *self,
MetaWindowActorPrivate *priv = self->priv;
cairo_rectangle_int_t bounding_rectangle = { 0, 0, width, height };
if (priv->bounding_region != NULL)
{
cairo_rectangle_int_t old_bounding_rectangle;
cairo_region_get_extents (priv->bounding_region, &old_bounding_rectangle);
if (old_bounding_rectangle.width == width && old_bounding_rectangle.height == height)
return;
}
meta_window_actor_clear_bounding_region (self);
priv->bounding_region = cairo_region_create_rectangle (&bounding_rectangle);
/* When we're shaped, we use the shape region to generate the shadow; the shape
* region only changes when we get ShapeNotify event; but for unshaped windows
* we generate the shadow from the bounding region, so we need to recompute
* the shadow when the size changes.
*/
if (!priv->shaped)
meta_window_actor_invalidate_shadow (self);
g_signal_emit (self, signals[SIZE_CHANGED], 0);
}
static void
@@ -1497,30 +1753,12 @@ meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
cairo_region_t *beneath_region)
{
MetaWindowActorPrivate *priv = self->priv;
gboolean appears_focused = meta_window_appears_focused (priv->window);
if (priv->shadow)
if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow)
{
cairo_rectangle_int_t shadow_rect;
ClutterActorBox box;
cairo_region_overlap_t overlap;
/* We could compute an full clip region as we do for the window
* texture, but the shadow is relatively cheap to draw, and
* a little more complex to clip, so we just catch the case where
* the shadow is completely obscured and doesn't need to be drawn
* at all.
*/
clutter_actor_get_allocation_box (priv->shadow, &box);
shadow_rect.x = roundf (box.x1);
shadow_rect.y = roundf (box.y1);
shadow_rect.width = roundf (box.x2 - box.x1);
shadow_rect.height = roundf (box.y2 - box.y1);
overlap = cairo_region_contains_rectangle (beneath_region, &shadow_rect);
tidy_texture_frame_set_needs_paint (TIDY_TEXTURE_FRAME (priv->shadow),
overlap != CAIRO_REGION_OVERLAP_OUT);
meta_window_actor_clear_shadow_clip (self);
priv->shadow_clip = cairo_region_copy (beneath_region);
}
}
@@ -1538,8 +1776,7 @@ meta_window_actor_reset_visible_regions (MetaWindowActor *self)
meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
NULL);
if (priv->shadow)
tidy_texture_frame_set_needs_paint (TIDY_TEXTURE_FRAME (priv->shadow), TRUE);
meta_window_actor_clear_shadow_clip (self);
}
static void
@@ -1552,7 +1789,6 @@ check_needs_pixmap (MetaWindowActor *self)
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
MetaCompositor *compositor;
Window xwindow = priv->xwindow;
gboolean full = FALSE;
if (!priv->needs_pixmap)
return;
@@ -1613,21 +1849,18 @@ check_needs_pixmap (MetaWindowActor *self)
* do it here.
* See: http://bugzilla.clutter-project.org/show_bug.cgi?id=2236
*/
if (!clutter_glx_texture_pixmap_using_extension (
CLUTTER_GLX_TEXTURE_PIXMAP (priv->actor)))
#ifdef HAVE_GLX_TEXTURE_PIXMAP
if (G_UNLIKELY (!clutter_glx_texture_pixmap_using_extension (
CLUTTER_GLX_TEXTURE_PIXMAP (priv->actor))))
g_warning ("NOTE: Not using GLX TFP!\n");
#endif
g_object_get (priv->actor,
"pixmap-width", &pxm_width,
"pixmap-height", &pxm_height,
NULL);
if (priv->shadow)
clutter_actor_set_size (priv->shadow, pxm_width, pxm_height);
meta_window_actor_update_bounding_region (self, pxm_width, pxm_height);
full = TRUE;
}
meta_error_trap_pop (display);
@@ -1635,6 +1868,79 @@ check_needs_pixmap (MetaWindowActor *self)
priv->needs_pixmap = FALSE;
}
static void
check_needs_shadow (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
MetaShadow *old_shadow = NULL;
MetaShadow **shadow_location;
gboolean recompute_shadow;
gboolean should_have_shadow;
gboolean appears_focused;
if (!priv->mapped)
return;
/* Calling meta_window_actor_has_shadow() here at every pre-paint is cheap
* and avoids the need to explicitly handle window type changes, which
* we would do if tried to keep track of when we might be adding or removing
* a shadow more explicitly. We only keep track of changes to the *shape* of
* the shadow with priv->recompute_shadow.
*/
should_have_shadow = meta_window_actor_has_shadow (self);
appears_focused = meta_window_appears_focused (priv->window);
if (appears_focused)
{
recompute_shadow = priv->recompute_focused_shadow;
priv->recompute_focused_shadow = FALSE;
shadow_location = &priv->focused_shadow;
}
else
{
recompute_shadow = priv->recompute_unfocused_shadow;
priv->recompute_unfocused_shadow = FALSE;
shadow_location = &priv->unfocused_shadow;
}
if (!should_have_shadow || recompute_shadow)
{
if (*shadow_location != NULL)
{
old_shadow = *shadow_location;
*shadow_location = NULL;
}
}
if (*shadow_location == NULL && should_have_shadow)
{
if (priv->shadow_shape == NULL)
{
if (priv->shaped && priv->shape_region)
priv->shadow_shape = meta_window_shape_new (priv->shape_region);
else if (priv->bounding_region)
priv->shadow_shape = meta_window_shape_new (priv->bounding_region);
}
if (priv->shadow_shape != NULL)
{
MetaShadowFactory *factory = meta_shadow_factory_get_default ();
const char *shadow_class = meta_window_actor_get_shadow_class (self);
cairo_rectangle_int_t shape_bounds;
meta_window_actor_get_shape_bounds (self, &shape_bounds);
*shadow_location = meta_shadow_factory_get_shadow (factory,
priv->shadow_shape,
shape_bounds.width, shape_bounds.height,
shadow_class, appears_focused);
}
}
if (old_shadow != NULL)
meta_shadow_unref (old_shadow);
}
static gboolean
is_frozen (MetaWindowActor *self)
{
@@ -1733,6 +2039,7 @@ check_needs_reshape (MetaWindowActor *self)
#endif
priv->needs_reshape = FALSE;
meta_window_actor_invalidate_shadow (self);
}
void
@@ -1743,6 +2050,11 @@ meta_window_actor_update_shape (MetaWindowActor *self,
priv->shaped = shaped;
priv->needs_reshape = TRUE;
if (priv->shadow_shape != NULL)
{
meta_window_shape_unref (priv->shadow_shape);
priv->shadow_shape = NULL;
}
clutter_actor_queue_redraw (priv->actor);
}
@@ -1770,8 +2082,19 @@ meta_window_actor_pre_paint (MetaWindowActor *self)
priv->received_damage = FALSE;
}
check_needs_reshape (self);
check_needs_pixmap (self);
check_needs_reshape (self);
check_needs_shadow (self);
}
void
meta_window_actor_invalidate_shadow (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
priv->recompute_focused_shadow = TRUE;
priv->recompute_unfocused_shadow = TRUE;
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
void

View File

@@ -5,8 +5,11 @@
#define _ISOC99_SOURCE /* for roundf */
#include <math.h>
#include <gdk/gdk.h> /* for gdk_rectangle_intersect() */
#include "meta-window-actor-private.h"
#include "meta-window-group.h"
#include "meta-background-actor.h"
struct _MetaWindowGroupClass
{
@@ -102,7 +105,9 @@ meta_window_group_paint (ClutterActor *actor)
{
MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
cairo_region_t *visible_region;
GLboolean scissor_test;
cairo_rectangle_int_t screen_rect = { 0 };
cairo_rectangle_int_t scissor_rect;
GList *children, *l;
/* We walk the list from top to bottom (opposite of painting order),
@@ -118,35 +123,67 @@ meta_window_group_paint (ClutterActor *actor)
* optimization, however.)
*/
meta_screen_get_size (window_group->screen, &screen_rect.width, &screen_rect.height);
visible_region = cairo_region_create_rectangle (&screen_rect);
/* When doing a partial stage paint, Clutter will set the GL scissor
* box to the clip rectangle for the partial repaint. We combine the screen
* rectangle with the scissor box to get the region we need to
* paint. (Strangely, the scissor box sometimes seems to be bigger
* than the stage ... Clutter should probably be clampimg)
*/
glGetBooleanv (GL_SCISSOR_TEST, &scissor_test);
if (scissor_test)
{
GLint scissor_box[4];
glGetIntegerv (GL_SCISSOR_BOX, scissor_box);
scissor_rect.x = scissor_box[0];
scissor_rect.y = screen_rect.height - (scissor_box[1] + scissor_box[3]);
scissor_rect.width = scissor_box[2];
scissor_rect.height = scissor_box[3];
gdk_rectangle_intersect (&scissor_rect, &screen_rect, &scissor_rect);
}
else
{
scissor_rect = screen_rect;
}
visible_region = cairo_region_create_rectangle (&scissor_rect);
for (l = children; l; l = l->next)
{
MetaWindowActor *window_actor;
gboolean x, y;
if (!META_IS_WINDOW_ACTOR (l->data) || !CLUTTER_ACTOR_IS_VISIBLE (l->data))
if (!CLUTTER_ACTOR_IS_VISIBLE (l->data))
continue;
window_actor = l->data;
if (!actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))
continue;
/* Temporarily move to the coordinate system of the actor */
cairo_region_translate (visible_region, - x, - y);
meta_window_actor_set_visible_region (window_actor, visible_region);
if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
if (META_IS_WINDOW_ACTOR (l->data))
{
cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
if (obscured_region)
cairo_region_subtract (visible_region, obscured_region);
}
MetaWindowActor *window_actor = l->data;
gboolean x, y;
meta_window_actor_set_visible_region_beneath (window_actor, visible_region);
cairo_region_translate (visible_region, x, y);
if (!actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))
continue;
/* Temporarily move to the coordinate system of the actor */
cairo_region_translate (visible_region, - x, - y);
meta_window_actor_set_visible_region (window_actor, visible_region);
if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
{
cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
if (obscured_region)
cairo_region_subtract (visible_region, obscured_region);
}
meta_window_actor_set_visible_region_beneath (window_actor, visible_region);
cairo_region_translate (visible_region, x, y);
}
else if (META_IS_BACKGROUND_ACTOR (l->data))
{
MetaBackgroundActor *background_actor = l->data;
meta_background_actor_set_visible_region (background_actor, visible_region);
}
}
cairo_region_destroy (visible_region);
@@ -158,13 +195,17 @@ meta_window_group_paint (ClutterActor *actor)
*/
for (l = children; l; l = l->next)
{
MetaWindowActor *window_actor;
if (!META_IS_WINDOW_ACTOR (l->data))
continue;
window_actor = l->data;
meta_window_actor_reset_visible_regions (window_actor);
if (META_IS_WINDOW_ACTOR (l->data))
{
MetaWindowActor *window_actor = l->data;
window_actor = l->data;
meta_window_actor_reset_visible_regions (window_actor);
}
else if (META_IS_BACKGROUND_ACTOR (l->data))
{
MetaBackgroundActor *background_actor = l->data;
meta_background_actor_set_visible_region (background_actor, NULL);
}
}
g_list_free (children);

View File

@@ -0,0 +1,254 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* MetaWindowShape
*
* Extracted invariant window shape
*
* Copyright (C) 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
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <string.h>
#include "meta-window-shape.h"
#include "region-utils.h"
struct _MetaWindowShape
{
guint ref_count;
int top, right, bottom, left;
int n_rectangles;
cairo_rectangle_int_t *rectangles;
guint hash;
};
MetaWindowShape *
meta_window_shape_new (cairo_region_t *region)
{
MetaWindowShape *shape;
MetaRegionIterator iter;
cairo_rectangle_int_t extents;
int max_yspan_y1 = 0;
int max_yspan_y2 = 0;
int max_xspan_x1 = -1;
int max_xspan_x2 = -1;
guint hash;
shape = g_slice_new0 (MetaWindowShape);
shape->ref_count = 1;
cairo_region_get_extents (region, &extents);
shape->n_rectangles = cairo_region_num_rectangles (region);
if (shape->n_rectangles == 0)
{
shape->rectangles = NULL;
shape->top = shape->right = shape->bottom = shape->left = 0;
shape->hash = 0;
return shape;
}
for (meta_region_iterator_init (&iter, region);
!meta_region_iterator_at_end (&iter);
meta_region_iterator_next (&iter))
{
int max_line_xspan_x1 = -1;
int max_line_xspan_x2 = -1;
if (iter.rectangle.width > max_line_xspan_x2 - max_line_xspan_x1)
{
max_line_xspan_x1 = iter.rectangle.x;
max_line_xspan_x2 = iter.rectangle.x + iter.rectangle.width;
}
if (iter.line_end)
{
if (iter.rectangle.height > max_yspan_y2 - max_yspan_y1)
{
max_yspan_y1 = iter.rectangle.y;
max_yspan_y2 = iter.rectangle.y + iter.rectangle.height;
}
if (max_xspan_x1 < 0) /* First line */
{
max_xspan_x1 = max_line_xspan_x1;
max_xspan_x2 = max_line_xspan_x2;
}
else
{
max_xspan_x1 = MAX (max_xspan_x1, max_line_xspan_x1);
max_xspan_x2 = MIN (max_xspan_x2, max_line_xspan_x2);
if (max_xspan_x2 < max_xspan_x1)
max_xspan_x2 = max_xspan_x1;
}
}
}
#if 0
g_print ("xspan: %d -> %d, yspan: %d -> %d\n",
max_xspan_x1, max_xspan_x2,
max_yspan_y1, max_yspan_y2);
#endif
shape->top = max_yspan_y1 - extents.y;
shape->right = extents.x + extents.width - max_xspan_x2;
shape->bottom = extents.y + extents.height - max_yspan_y2;
shape->left = max_xspan_x1 - extents.x;
shape->rectangles = g_new (cairo_rectangle_int_t, shape->n_rectangles);
hash = 0;
for (meta_region_iterator_init (&iter, region);
!meta_region_iterator_at_end (&iter);
meta_region_iterator_next (&iter))
{
int x1, x2, y1, y2;
x1 = iter.rectangle.x;
x2 = iter.rectangle.x + iter.rectangle.width;
y1 = iter.rectangle.y;
y2 = iter.rectangle.y + iter.rectangle.height;
if (x1 > max_xspan_x1)
x1 -= MIN (x1, max_xspan_x2 - 1) - max_xspan_x1;
if (x2 > max_xspan_x1)
x2 -= MIN (x2, max_xspan_x2 - 1) - max_xspan_x1;
if (y1 > max_yspan_y1)
y1 -= MIN (y1, max_yspan_y2 - 1) - max_yspan_y1;
if (y2 > max_yspan_y1)
y2 -= MIN (y2, max_yspan_y2 - 1) - max_yspan_y1;
shape->rectangles[iter.i].x = x1 - extents.x;
shape->rectangles[iter.i].y = y1 - extents.y;
shape->rectangles[iter.i].width = x2 - x1;
shape->rectangles[iter.i].height = y2 - y1;
#if 0
g_print ("%d: +%d+%dx%dx%d => +%d+%dx%dx%d\n",
iter.i, iter.rectangle.x, iter.rectangle.y, iter.rectangle.width, iter.rectangle.height,
shape->rectangles[iter.i].x, shape->rectangles[iter.i].y,
hape->rectangles[iter.i].width, shape->rectangles[iter.i].height);
#endif
hash = hash * 31 + x1 * 17 + x2 * 27 + y1 * 37 + y2 * 43;
}
shape->hash = hash;
#if 0
g_print ("%d %d %d %d: %#x\n\n", shape->top, shape->right, shape->bottom, shape->left, shape->hash);
#endif
return shape;
}
MetaWindowShape *
meta_window_shape_ref (MetaWindowShape *shape)
{
shape->ref_count++;
return shape;
}
void
meta_window_shape_unref (MetaWindowShape *shape)
{
shape->ref_count--;
if (shape->ref_count == 0)
{
g_free (shape->rectangles);
g_slice_free (MetaWindowShape, shape);
}
}
guint
meta_window_shape_hash (MetaWindowShape *shape)
{
return shape->hash;
}
gboolean
meta_window_shape_equal (MetaWindowShape *shape_a,
MetaWindowShape *shape_b)
{
if (shape_a->n_rectangles != shape_b->n_rectangles)
return FALSE;
return memcmp (shape_a->rectangles, shape_b->rectangles,
sizeof (cairo_rectangle_int_t) * shape_a->n_rectangles) == 0;
}
void
meta_window_shape_get_borders (MetaWindowShape *shape,
int *border_top,
int *border_right,
int *border_bottom,
int *border_left)
{
if (border_top)
*border_top = shape->top;
if (border_right)
*border_right = shape->right;
if (border_bottom)
*border_bottom = shape->bottom;
if (border_left)
*border_left = shape->left;
}
/**
* meta_window_shape_to_region:
* @shape: a #MetaWindowShape
* @center_width: size of the central region horizontally
* @center_height: size of the central region vertically
*
* Converts the shape to to a cairo_region_t using the given width
* and height for the central scaled region.
*
* Return value: a newly created region
*/
cairo_region_t *
meta_window_shape_to_region (MetaWindowShape *shape,
int center_width,
int center_height)
{
cairo_region_t *region;
int i;
region = cairo_region_create ();
for (i = 0; i < shape->n_rectangles; i++)
{
cairo_rectangle_int_t rect = shape->rectangles[i];
if (rect.x <= shape->left && rect.x + rect.width >= shape->left + 1)
rect.width += center_width;
else if (rect.x >= shape->left + 1)
rect.x += center_width;
if (rect.y <= shape->top && rect.y + rect.height >= shape->top + 1)
rect.height += center_height;
else if (rect.y >= shape->top + 1)
rect.y += center_height;
cairo_region_union_rectangle (region, &rect);
}
return region;
}

View File

@@ -0,0 +1,60 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* MetaWindowShape
*
* Extracted invariant window shape
*
* Copyright (C) 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
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef __META_WINDOW_SHAPE_H__
#define __META_WINDOW_SHAPE_H__
#include <cairo.h>
#include <glib.h>
/**
* MetaWindowShape:
* #MetaWindowShape represents a 9-sliced region with borders on all sides that
* are unscaled, and a constant central region that is scaled. For example,
* the regions representing two windows that are rounded rectangles,
* with the same corner radius but different sizes, have the
* same MetaWindowShape.
*
* #MetaWindowShape is designed to be used as part of a hash table key, so has
* efficient hash and equal functions.
*/
typedef struct _MetaWindowShape MetaWindowShape;
MetaWindowShape * meta_window_shape_new (cairo_region_t *region);
MetaWindowShape * meta_window_shape_ref (MetaWindowShape *shape);
void meta_window_shape_unref (MetaWindowShape *shape);
guint meta_window_shape_hash (MetaWindowShape *shape);
gboolean meta_window_shape_equal (MetaWindowShape *shape_a,
MetaWindowShape *shape_b);
void meta_window_shape_get_borders (MetaWindowShape *shape,
int *border_top,
int *border_right,
int *border_bottom,
int *border_left);
cairo_region_t *meta_window_shape_to_region (MetaWindowShape *shape,
int center_width,
int center_height);
#endif /* __META_WINDOW_SHAPE_H __*/

View File

@@ -319,12 +319,10 @@ switch_workspace (MetaPlugin *plugin,
{
MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
GList *l;
gint n_workspaces;
ClutterActor *workspace0 = clutter_group_new ();
ClutterActor *workspace1 = clutter_group_new ();
ClutterActor *stage;
int screen_width, screen_height;
MetaScreen *screen = meta_plugin_get_screen (plugin);
ClutterAnimation *animation;
stage = meta_plugin_get_stage (plugin);
@@ -350,8 +348,6 @@ switch_workspace (MetaPlugin *plugin,
return;
}
n_workspaces = meta_screen_get_n_workspaces (screen);
l = g_list_last (meta_plugin_get_window_actors (plugin));
while (l)

View File

@@ -0,0 +1,336 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Utilities for region manipulation
*
* Copyright (C) 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
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "region-utils.h"
#include <math.h>
/* MetaRegionBuilder */
/* Various algorithms in this file require unioning together a set of rectangles
* that are unsorted or overlap; unioning such a set of rectangles 1-by-1
* using cairo_region_union_rectangle() produces O(N^2) behavior (if the union
* adds or removes rectangles in the middle of the region, then it has to
* move all the rectangles after that.) To avoid this behavior, MetaRegionBuilder
* creates regions for small groups of rectangles and merges them together in
* a binary tree.
*
* Possible improvement: From a glance at the code, accumulating all the rectangles
* into a flat array and then calling the (not usefully documented)
* cairo_region_create_rectangles() would have the same behavior and would be
* simpler and a bit more efficient.
*/
/* Optimium performance seems to be with MAX_CHUNK_RECTANGLES=4; 8 is about 10% slower.
* But using 8 may be more robust to systems with slow malloc(). */
#define MAX_CHUNK_RECTANGLES 8
#define MAX_LEVELS 16
typedef struct
{
/* To merge regions in binary tree order, we need to keep track of
* the regions that we've already merged together at different
* levels of the tree. We fill in an array in the pattern:
*
* |a |
* |b |a |
* |c | |ab |
* |d |c |ab |
* |e | | |abcd|
*/
cairo_region_t *levels[MAX_LEVELS];
int n_levels;
} MetaRegionBuilder;
static void
meta_region_builder_init (MetaRegionBuilder *builder)
{
int i;
for (i = 0; i < MAX_LEVELS; i++)
builder->levels[i] = NULL;
builder->n_levels = 1;
}
static void
meta_region_builder_add_rectangle (MetaRegionBuilder *builder,
int x,
int y,
int width,
int height)
{
cairo_rectangle_int_t rect;
int i;
if (builder->levels[0] == NULL)
builder->levels[0] = cairo_region_create ();
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
cairo_region_union_rectangle (builder->levels[0], &rect);
if (cairo_region_num_rectangles (builder->levels[0]) >= MAX_CHUNK_RECTANGLES)
{
for (i = 1; i < builder->n_levels + 1; i++)
{
if (builder->levels[i] == NULL)
{
if (i < MAX_LEVELS)
{
builder->levels[i] = builder->levels[i - 1];
builder->levels[i - 1] = NULL;
if (i == builder->n_levels)
builder->n_levels++;
}
break;
}
else
{
cairo_region_union (builder->levels[i], builder->levels[i - 1]);
cairo_region_destroy (builder->levels[i - 1]);
builder->levels[i - 1] = NULL;
}
}
}
}
static cairo_region_t *
meta_region_builder_finish (MetaRegionBuilder *builder)
{
cairo_region_t *result = NULL;
int i;
for (i = 0; i < builder->n_levels; i++)
{
if (builder->levels[i])
{
if (result == NULL)
result = builder->levels[i];
else
{
cairo_region_union(result, builder->levels[i]);
cairo_region_destroy (builder->levels[i]);
}
}
}
if (result == NULL)
result = cairo_region_create ();
return result;
}
/* MetaRegionIterator */
void
meta_region_iterator_init (MetaRegionIterator *iter,
cairo_region_t *region)
{
iter->region = region;
iter->i = 0;
iter->n_rectangles = cairo_region_num_rectangles (region);
iter->line_start = TRUE;
if (iter->n_rectangles > 1)
{
cairo_region_get_rectangle (region, 0, &iter->rectangle);
cairo_region_get_rectangle (region, 1, &iter->next_rectangle);
iter->line_end = iter->next_rectangle.y != iter->rectangle.y;
}
else if (iter->n_rectangles > 0)
{
cairo_region_get_rectangle (region, 0, &iter->rectangle);
iter->line_end = TRUE;
}
}
gboolean
meta_region_iterator_at_end (MetaRegionIterator *iter)
{
return iter->i >= iter->n_rectangles;
}
void
meta_region_iterator_next (MetaRegionIterator *iter)
{
iter->i++;
iter->rectangle = iter->next_rectangle;
iter->line_start = iter->line_end;
if (iter->i + 1 < iter->n_rectangles)
{
cairo_region_get_rectangle (iter->region, iter->i + 1, &iter->next_rectangle);
iter->line_end = iter->next_rectangle.y != iter->rectangle.y;
}
else
{
iter->line_end = TRUE;
}
}
static void
add_expanded_rect (MetaRegionBuilder *builder,
int x,
int y,
int width,
int height,
int x_amount,
int y_amount,
gboolean flip)
{
if (flip)
meta_region_builder_add_rectangle (builder,
y - y_amount, x - x_amount,
height + 2 * y_amount, width + 2 * x_amount);
else
meta_region_builder_add_rectangle (builder,
x - x_amount, y - y_amount,
width + 2 * x_amount, height + 2 * y_amount);
}
static cairo_region_t *
expand_region (cairo_region_t *region,
int x_amount,
int y_amount,
gboolean flip)
{
MetaRegionBuilder builder;
int n;
int i;
meta_region_builder_init (&builder);
n = cairo_region_num_rectangles (region);
for (i = 0; i < n; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
add_expanded_rect (&builder,
rect.x, rect.y, rect.width, rect.height,
x_amount, y_amount, flip);
}
return meta_region_builder_finish (&builder);
}
/* This computes a (clipped version) of the inverse of the region
* and expands it by the given amount */
static cairo_region_t *
expand_region_inverse (cairo_region_t *region,
int x_amount,
int y_amount,
gboolean flip)
{
MetaRegionBuilder builder;
MetaRegionIterator iter;
cairo_rectangle_int_t extents;
cairo_region_t *chunk;
int last_x;
meta_region_builder_init (&builder);
cairo_region_get_extents (region, &extents);
add_expanded_rect (&builder,
extents.x, extents.y - 1, extents.width, 1,
x_amount, y_amount, flip);
add_expanded_rect (&builder,
extents.x - 1, extents.y, 1, extents.height,
x_amount, y_amount, flip);
add_expanded_rect (&builder,
extents.x + extents.width, extents.y, 1, extents.height,
x_amount, y_amount, flip);
add_expanded_rect (&builder,
extents.x, extents.y + extents.height, extents.width, 1,
x_amount, y_amount, flip);
chunk = NULL;
last_x = extents.x;
for (meta_region_iterator_init (&iter, region);
!meta_region_iterator_at_end (&iter);
meta_region_iterator_next (&iter))
{
if (chunk == NULL)
chunk = cairo_region_create ();
if (iter.rectangle.x > last_x)
add_expanded_rect (&builder,
last_x, iter.rectangle.y,
iter.rectangle.x - last_x, iter.rectangle.height,
x_amount, y_amount, flip);
if (iter.line_end)
{
if (extents.x + extents.width > iter.rectangle.x + iter.rectangle.width)
add_expanded_rect (&builder,
iter.rectangle.x + iter.rectangle.width, iter.rectangle.y,
(extents.x + extents.width) - (iter.rectangle.x + iter.rectangle.width), iter.rectangle.height,
x_amount, y_amount, flip);
last_x = extents.x;
}
else
last_x = iter.rectangle.x + iter.rectangle.width;
}
return meta_region_builder_finish (&builder);
}
/**
* meta_make_border_region:
* @region: a #cairo_region_t
* @x_amount: distance from the border to extend horizontally
* @y_amount: distance from the border to extend vertically
* @flip: if true, the result is computed with x and y interchanged
*
* Computes the "border region" of a given region, which is roughly
* speaking the set of points near the boundary of the region. If we
* define the operation of growing a region as computing the set of
* points within a given manhattan distance of the region, then the
* border is 'grow(region) intersect grow(inverse(region))'.
*
* If we create an image by filling the region with a solid color,
* the border is the region affected by blurring the region.
*
* Return value: a new region which is the border of the given region
*/
cairo_region_t *
meta_make_border_region (cairo_region_t *region,
int x_amount,
int y_amount,
gboolean flip)
{
cairo_region_t *border_region;
cairo_region_t *inverse_region;
border_region = expand_region (region, x_amount, y_amount, flip);
inverse_region = expand_region_inverse (region, x_amount, y_amount, flip);
cairo_region_intersect (border_region, inverse_region);
cairo_region_destroy (inverse_region);
return border_region;
}

View File

@@ -0,0 +1,76 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Utilities for region manipulation
*
* Copyright (C) 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
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef __META_REGION_UTILS_H__
#define __META_REGION_UTILS_H__
#include <clutter/clutter.h>
#include <cairo.h>
#include <glib.h>
/**
* MetaRegionIterator:
* @region: region being iterated
* @rectangle: current rectangle
* @line_start: whether the current rectangle starts a horizontal band
* @line_end: whether the current rectangle ends a horizontal band
*
* cairo_region_t is a yx banded region; sometimes its useful to iterate through
* such a region treating the start and end of each horizontal band in a distinct
* fashion.
*
* Usage:
*
* MetaRegionIterator iter;
* for (meta_region_iterator_init (&iter, region);
* !meta_region_iterator_at_end (&iter);
* meta_region_iterator_next (&iter))
* {
* [ Use iter.rectangle, iter.line_start, iter.line_end ]
* }
*/
typedef struct _MetaRegionIterator MetaRegionIterator;
struct _MetaRegionIterator {
cairo_region_t *region;
cairo_rectangle_int_t rectangle;
gboolean line_start;
gboolean line_end;
int i;
/*< private >*/
int n_rectangles;
cairo_rectangle_int_t next_rectangle;
};
void meta_region_iterator_init (MetaRegionIterator *iter,
cairo_region_t *region);
gboolean meta_region_iterator_at_end (MetaRegionIterator *iter);
void meta_region_iterator_next (MetaRegionIterator *iter);
cairo_region_t *meta_make_border_region (cairo_region_t *region,
int x_amount,
int y_amount,
gboolean flip);
#endif /* __META_REGION_UTILS_H__ */

View File

@@ -1,350 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#define _GNU_SOURCE /* For M_PI */
#include <math.h>
#include "compositor-private.h"
#include "shadow.h"
#include "tidy/tidy-texture-frame.h"
#define SHADOW_RADIUS 8
#define SHADOW_OPACITY 0.9
#define SHADOW_OFFSET_X (SHADOW_RADIUS)
#define SHADOW_OFFSET_Y (SHADOW_RADIUS)
#define MAX_TILE_SZ 8 /* Must be <= shaddow radius */
#define TILE_WIDTH (3*MAX_TILE_SZ)
#define TILE_HEIGHT (3*MAX_TILE_SZ)
static unsigned char* shadow_gaussian_make_tile (void);
ClutterActor *
meta_create_shadow_frame (MetaCompositor *compositor)
{
ClutterActor *frame;
if (!compositor->shadow_src)
{
guchar *data;
data = shadow_gaussian_make_tile ();
compositor->shadow_src = clutter_texture_new ();
clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (compositor->shadow_src),
data,
TRUE,
TILE_WIDTH,
TILE_HEIGHT,
TILE_WIDTH*4,
4,
0,
NULL);
g_free (data);
}
frame = tidy_texture_frame_new (CLUTTER_TEXTURE (compositor->shadow_src),
MAX_TILE_SZ,
MAX_TILE_SZ,
MAX_TILE_SZ,
MAX_TILE_SZ);
clutter_actor_set_position (frame,
SHADOW_OFFSET_X , SHADOW_OFFSET_Y);
return frame;
}
typedef struct GaussianMap
{
int size;
double * data;
} GaussianMap;
static double
gaussian (double r, double x, double y)
{
return ((1 / (sqrt (2 * M_PI * r))) *
exp ((- (x * x + y * y)) / (2 * r * r)));
}
static GaussianMap *
make_gaussian_map (double r)
{
GaussianMap *c;
int size = ((int) ceil ((r * 3)) + 1) & ~1;
int center = size / 2;
int x, y;
double t = 0.0;
double g;
c = g_malloc (sizeof (GaussianMap) + size * size * sizeof (double));
c->size = size;
c->data = (double *) (c + 1);
for (y = 0; y < size; y++)
for (x = 0; x < size; x++)
{
g = gaussian (r, (double) (x - center), (double) (y - center));
t += g;
c->data[y * size + x] = g;
}
for (y = 0; y < size; y++)
for (x = 0; x < size; x++)
c->data[y*size + x] /= t;
return c;
}
static unsigned char
sum_gaussian (GaussianMap * map, double opacity,
int x, int y, int width, int height)
{
int fx, fy;
double * g_data;
double * g_line = map->data;
int g_size = map->size;
int center = g_size / 2;
int fx_start, fx_end;
int fy_start, fy_end;
double v;
unsigned int r;
/*
* Compute set of filter values which are "in range",
* that's the set with:
* 0 <= x + (fx-center) && x + (fx-center) < width &&
* 0 <= y + (fy-center) && y + (fy-center) < height
*
* 0 <= x + (fx - center) x + fx - center < width
* center - x <= fx fx < width + center - x
*/
fx_start = center - x;
if (fx_start < 0)
fx_start = 0;
fx_end = width + center - x;
if (fx_end > g_size)
fx_end = g_size;
fy_start = center - y;
if (fy_start < 0)
fy_start = 0;
fy_end = height + center - y;
if (fy_end > g_size)
fy_end = g_size;
g_line = g_line + fy_start * g_size + fx_start;
v = 0;
for (fy = fy_start; fy < fy_end; fy++)
{
g_data = g_line;
g_line += g_size;
for (fx = fx_start; fx < fx_end; fx++)
v += *g_data++;
}
if (v > 1)
v = 1;
v *= (opacity * 255.0);
r = (unsigned int) v;
return (unsigned char) r;
}
static unsigned char *
shadow_gaussian_make_tile ()
{
unsigned char * data;
int size;
int center;
int x, y;
unsigned char d;
int pwidth, pheight;
double opacity = SHADOW_OPACITY;
static GaussianMap * gaussian_map = NULL;
struct _mypixel
{
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
} * _d;
if (!gaussian_map)
gaussian_map =
make_gaussian_map (SHADOW_RADIUS);
size = gaussian_map->size;
center = size / 2;
/* Top & bottom */
pwidth = MAX_TILE_SZ;
pheight = MAX_TILE_SZ;
data = g_malloc0 (4 * TILE_WIDTH * TILE_HEIGHT);
_d = (struct _mypixel*) data;
/* N */
for (y = 0; y < pheight; y++)
{
d = sum_gaussian (gaussian_map, opacity,
center, y - center,
TILE_WIDTH, TILE_HEIGHT);
for (x = 0; x < pwidth; x++)
{
_d[y*3*pwidth + x + pwidth].r = 0;
_d[y*3*pwidth + x + pwidth].g = 0;
_d[y*3*pwidth + x + pwidth].b = 0;
_d[y*3*pwidth + x + pwidth].a = d;
}
}
/* S */
pwidth = MAX_TILE_SZ;
pheight = MAX_TILE_SZ;
for (y = 0; y < pheight; y++)
{
d = sum_gaussian (gaussian_map, opacity,
center, y - center,
TILE_WIDTH, TILE_HEIGHT);
for (x = 0; x < pwidth; x++)
{
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].r = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].g = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].b = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].a = d;
}
}
/* w */
pwidth = MAX_TILE_SZ;
pheight = MAX_TILE_SZ;
for (x = 0; x < pwidth; x++)
{
d = sum_gaussian (gaussian_map, opacity,
x - center, center,
TILE_WIDTH, TILE_HEIGHT);
for (y = 0; y < pheight; y++)
{
_d[y*3*pwidth + 3*pwidth*pheight + x].r = 0;
_d[y*3*pwidth + 3*pwidth*pheight + x].g = 0;
_d[y*3*pwidth + 3*pwidth*pheight + x].b = 0;
_d[y*3*pwidth + 3*pwidth*pheight + x].a = d;
}
}
/* E */
for (x = 0; x < pwidth; x++)
{
d = sum_gaussian (gaussian_map, opacity,
x - center, center,
TILE_WIDTH, TILE_HEIGHT);
for (y = 0; y < pheight; y++)
{
_d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].r = 0;
_d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].g = 0;
_d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].b = 0;
_d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].a = d;
}
}
/* NW */
pwidth = MAX_TILE_SZ;
pheight = MAX_TILE_SZ;
for (x = 0; x < pwidth; x++)
for (y = 0; y < pheight; y++)
{
d = sum_gaussian (gaussian_map, opacity,
x-center, y-center,
TILE_WIDTH, TILE_HEIGHT);
_d[y*3*pwidth + x].r = 0;
_d[y*3*pwidth + x].g = 0;
_d[y*3*pwidth + x].b = 0;
_d[y*3*pwidth + x].a = d;
}
/* SW */
for (x = 0; x < pwidth; x++)
for (y = 0; y < pheight; y++)
{
d = sum_gaussian (gaussian_map, opacity,
x-center, y-center,
TILE_WIDTH, TILE_HEIGHT);
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].r = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].g = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].b = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].a = d;
}
/* SE */
for (x = 0; x < pwidth; x++)
for (y = 0; y < pheight; y++)
{
d = sum_gaussian (gaussian_map, opacity,
x-center, y-center,
TILE_WIDTH, TILE_HEIGHT);
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) +
2*pwidth].r = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) +
2*pwidth].g = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) +
2*pwidth].b = 0;
_d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) +
2*pwidth].a = d;
}
/* NE */
for (x = 0; x < pwidth; x++)
for (y = 0; y < pheight; y++)
{
d = sum_gaussian (gaussian_map, opacity,
x-center, y-center,
TILE_WIDTH, TILE_HEIGHT);
_d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].r = 0;
_d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].g = 0;
_d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].b = 0;
_d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].a = d;
}
/* center */
pwidth = MAX_TILE_SZ;
pheight = MAX_TILE_SZ;
d = sum_gaussian (gaussian_map, opacity,
center, center, TILE_WIDTH, TILE_HEIGHT);
for (x = 0; x < pwidth; x++)
for (y = 0; y < pheight; y++)
{
_d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].r = 0;
_d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].g = 0;
_d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].b = 0;
_d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].a = 0;
}
return data;
}

View File

@@ -1,9 +0,0 @@
#ifndef SHADOW_H
#define SHADOW_H
#include <clutter/clutter.h>
#include "compositor.h"
ClutterActor *meta_create_shadow_frame (MetaCompositor *compositor);
#endif /* SHADOW_H */

View File

@@ -1,641 +0,0 @@
/* tidy-texture-frame.h: Expandible texture actor
*
* Copyright (C) 2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:tidy-texture-frame
* @short_description: Stretch a texture to fit the entire allocation
*
* #TidyTextureFrame
*
*/
#include <cogl/cogl.h>
#include "tidy-texture-frame.h"
#define TIDY_PARAM_READABLE \
(G_PARAM_READABLE | \
G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
#define TIDY_PARAM_READWRITE \
(G_PARAM_READABLE | G_PARAM_WRITABLE | \
G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
enum
{
PROP_0,
PROP_PARENT_TEXTURE,
PROP_LEFT,
PROP_TOP,
PROP_RIGHT,
PROP_BOTTOM
};
G_DEFINE_TYPE (TidyTextureFrame, tidy_texture_frame, CLUTTER_TYPE_ACTOR);
#define TIDY_TEXTURE_FRAME_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFramePrivate))
struct _TidyTextureFramePrivate
{
ClutterTexture *parent_texture;
gfloat left;
gfloat top;
gfloat right;
gfloat bottom;
CoglHandle material;
guint needs_paint : 1;
};
static void
tidy_texture_frame_get_preferred_width (ClutterActor *self,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv;
if (G_UNLIKELY (priv->parent_texture == NULL))
{
if (min_width_p)
*min_width_p = 0;
if (natural_width_p)
*natural_width_p = 0;
}
else
{
ClutterActorClass *klass;
/* by directly querying the parent texture's class implementation
* we are going around any override mechanism the parent texture
* might have in place, and we ask directly for the original
* preferred width
*/
klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture);
klass->get_preferred_width (CLUTTER_ACTOR (priv->parent_texture),
for_height,
min_width_p,
natural_width_p);
}
}
static void
tidy_texture_frame_get_preferred_height (ClutterActor *self,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv;
if (G_UNLIKELY (priv->parent_texture == NULL))
{
if (min_height_p)
*min_height_p = 0;
if (natural_height_p)
*natural_height_p = 0;
}
else
{
ClutterActorClass *klass;
/* by directly querying the parent texture's class implementation
* we are going around any override mechanism the parent texture
* might have in place, and we ask directly for the original
* preferred height
*/
klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture);
klass->get_preferred_height (CLUTTER_ACTOR (priv->parent_texture),
for_width,
min_height_p,
natural_height_p);
}
}
static void
tidy_texture_frame_realize (ClutterActor *self)
{
TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv;
if (priv->material != COGL_INVALID_HANDLE)
return;
priv->material = cogl_material_new ();
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
}
static void
tidy_texture_frame_unrealize (ClutterActor *self)
{
TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv;
if (priv->material == COGL_INVALID_HANDLE)
return;
cogl_handle_unref (priv->material);
priv->material = COGL_INVALID_HANDLE;
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
}
static void
tidy_texture_frame_paint (ClutterActor *self)
{
TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv;
CoglHandle cogl_texture = COGL_INVALID_HANDLE;
ClutterActorBox box = { 0, };
gfloat width, height;
gfloat tex_width, tex_height;
gfloat ex, ey;
gfloat tx1, ty1, tx2, ty2;
guint8 opacity;
/* no need to paint stuff if we don't have a texture */
if (G_UNLIKELY (priv->parent_texture == NULL))
return;
if (!priv->needs_paint)
return;
/* parent texture may have been hidden, so need to make sure it gets
* realized
*/
if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_texture))
clutter_actor_realize (CLUTTER_ACTOR (priv->parent_texture));
cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture);
if (cogl_texture == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (cogl_texture);
tex_height = cogl_texture_get_height (cogl_texture);
clutter_actor_get_allocation_box (self, &box);
width = box.x2 - box.x1;
height = box.y2 - box.y1;
tx1 = priv->left / tex_width;
tx2 = (tex_width - priv->right) / tex_width;
ty1 = priv->top / tex_height;
ty2 = (tex_height - priv->bottom) / tex_height;
ex = width - priv->right;
if (ex < 0)
ex = priv->right; /* FIXME ? */
ey = height - priv->bottom;
if (ey < 0)
ey = priv->bottom; /* FIXME ? */
opacity = clutter_actor_get_paint_opacity (self);
g_assert (priv->material != COGL_INVALID_HANDLE);
/* set the source material using the parent texture's COGL handle */
cogl_material_set_color4ub (priv->material, opacity, opacity, opacity, opacity);
cogl_material_set_layer (priv->material, 0, cogl_texture);
cogl_set_source (priv->material);
/* top left corner */
cogl_rectangle_with_texture_coords (0, 0, priv->left, priv->top,
0.0, 0.0,
tx1, ty1);
/* top middle */
cogl_rectangle_with_texture_coords (priv->left, 0, ex, priv->top,
tx1, 0.0,
tx2, ty1);
/* top right */
cogl_rectangle_with_texture_coords (ex, 0, width, priv->top,
tx2, 0.0,
1.0, ty1);
/* mid left */
cogl_rectangle_with_texture_coords (0, priv->top, priv->left, ey,
0.0, ty1,
tx1, ty2);
/* center */
cogl_rectangle_with_texture_coords (priv->left, priv->top, ex, ey,
tx1, ty1,
tx2, ty2);
/* mid right */
cogl_rectangle_with_texture_coords (ex, priv->top, width, ey,
tx2, ty1,
1.0, ty2);
/* bottom left */
cogl_rectangle_with_texture_coords (0, ey, priv->left, height,
0.0, ty2,
tx1, 1.0);
/* bottom center */
cogl_rectangle_with_texture_coords (priv->left, ey, ex, height,
tx1, ty2,
tx2, 1.0);
/* bottom right */
cogl_rectangle_with_texture_coords (ex, ey, width, height,
tx2, ty2,
1.0, 1.0);
}
static inline void
tidy_texture_frame_set_frame_internal (TidyTextureFrame *frame,
gfloat left,
gfloat top,
gfloat right,
gfloat bottom)
{
TidyTextureFramePrivate *priv = frame->priv;
GObject *gobject = G_OBJECT (frame);
gboolean changed = FALSE;
g_object_freeze_notify (gobject);
if (priv->top != top)
{
priv->top = top;
g_object_notify (gobject, "top");
changed = TRUE;
}
if (priv->right != right)
{
priv->right = right;
g_object_notify (gobject, "right");
changed = TRUE;
}
if (priv->bottom != bottom)
{
priv->bottom = bottom;
g_object_notify (gobject, "bottom");
changed = TRUE;
}
if (priv->left != left)
{
priv->left = left;
g_object_notify (gobject, "left");
changed = TRUE;
}
if (changed && CLUTTER_ACTOR_IS_VISIBLE (frame))
clutter_actor_queue_redraw (CLUTTER_ACTOR (frame));
g_object_thaw_notify (gobject);
}
static void
tidy_texture_frame_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
TidyTextureFrame *frame = TIDY_TEXTURE_FRAME (gobject);
TidyTextureFramePrivate *priv = frame->priv;
switch (prop_id)
{
case PROP_PARENT_TEXTURE:
tidy_texture_frame_set_parent_texture (frame,
g_value_get_object (value));
break;
case PROP_TOP:
tidy_texture_frame_set_frame_internal (frame,
priv->left,
g_value_get_float (value),
priv->right,
priv->bottom);
break;
case PROP_RIGHT:
tidy_texture_frame_set_frame_internal (frame,
priv->top,
g_value_get_float (value),
priv->bottom,
priv->left);
break;
case PROP_BOTTOM:
tidy_texture_frame_set_frame_internal (frame,
priv->top,
priv->right,
g_value_get_float (value),
priv->left);
break;
case PROP_LEFT:
tidy_texture_frame_set_frame_internal (frame,
priv->top,
priv->right,
priv->bottom,
g_value_get_float (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
tidy_texture_frame_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (gobject)->priv;
switch (prop_id)
{
case PROP_PARENT_TEXTURE:
g_value_set_object (value, priv->parent_texture);
break;
case PROP_LEFT:
g_value_set_float (value, priv->left);
break;
case PROP_TOP:
g_value_set_float (value, priv->top);
break;
case PROP_RIGHT:
g_value_set_float (value, priv->right);
break;
case PROP_BOTTOM:
g_value_set_float (value, priv->bottom);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
tidy_texture_frame_dispose (GObject *gobject)
{
TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (gobject)->priv;
if (priv->parent_texture)
{
g_object_unref (priv->parent_texture);
priv->parent_texture = NULL;
}
if (priv->material)
{
cogl_handle_unref (priv->material);
priv->material = COGL_INVALID_HANDLE;
}
G_OBJECT_CLASS (tidy_texture_frame_parent_class)->dispose (gobject);
}
static void
tidy_texture_frame_class_init (TidyTextureFrameClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (gobject_class, sizeof (TidyTextureFramePrivate));
actor_class->get_preferred_width =
tidy_texture_frame_get_preferred_width;
actor_class->get_preferred_height =
tidy_texture_frame_get_preferred_height;
actor_class->realize = tidy_texture_frame_realize;
actor_class->unrealize = tidy_texture_frame_unrealize;
actor_class->paint = tidy_texture_frame_paint;
gobject_class->set_property = tidy_texture_frame_set_property;
gobject_class->get_property = tidy_texture_frame_get_property;
gobject_class->dispose = tidy_texture_frame_dispose;
pspec = g_param_spec_object ("parent-texture",
"Parent Texture",
"The parent ClutterTexture",
CLUTTER_TYPE_TEXTURE,
TIDY_PARAM_READWRITE |
G_PARAM_CONSTRUCT);
g_object_class_install_property (gobject_class, PROP_PARENT_TEXTURE, pspec);
pspec = g_param_spec_float ("left",
"Left",
"Left offset",
0, G_MAXFLOAT,
0,
TIDY_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_LEFT, pspec);
pspec = g_param_spec_float ("top",
"Top",
"Top offset",
0, G_MAXFLOAT,
0,
TIDY_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TOP, pspec);
pspec = g_param_spec_float ("bottom",
"Bottom",
"Bottom offset",
0, G_MAXFLOAT,
0,
TIDY_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_BOTTOM, pspec);
pspec = g_param_spec_float ("right",
"Right",
"Right offset",
0, G_MAXFLOAT,
0,
TIDY_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_RIGHT, pspec);
}
static void
tidy_texture_frame_init (TidyTextureFrame *self)
{
TidyTextureFramePrivate *priv;
self->priv = priv = TIDY_TEXTURE_FRAME_GET_PRIVATE (self);
priv->material = COGL_INVALID_HANDLE;
}
/**
* tidy_texture_frame_new:
* @texture: a #ClutterTexture or %NULL
* @left: left margin preserving its content
* @top: top margin preserving its content
* @right: right margin preserving its content
* @bottom: bottom margin preserving its content
*
* A #TidyTextureFrame is a specialized texture that efficiently clones
* an area of the given @texture while keeping preserving portions of the
* same texture.
*
* A #TidyTextureFrame can be used to make a rectangular texture fit a
* given size without stretching its borders.
*
* Return value: the newly created #TidyTextureFrame
*/
ClutterActor*
tidy_texture_frame_new (ClutterTexture *texture,
gfloat left,
gfloat top,
gfloat right,
gfloat bottom)
{
g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
return g_object_new (TIDY_TYPE_TEXTURE_FRAME,
"parent-texture", texture,
"left", left,
"top", top,
"right", right,
"bottom", bottom,
NULL);
}
ClutterTexture *
tidy_texture_frame_get_parent_texture (TidyTextureFrame *frame)
{
g_return_val_if_fail (TIDY_IS_TEXTURE_FRAME (frame), NULL);
return frame->priv->parent_texture;
}
void
tidy_texture_frame_set_parent_texture (TidyTextureFrame *frame,
ClutterTexture *texture)
{
TidyTextureFramePrivate *priv;
gboolean was_visible;
g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame));
g_return_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture));
priv = frame->priv;
was_visible = CLUTTER_ACTOR_IS_VISIBLE (frame);
if (priv->parent_texture == texture)
return;
if (priv->parent_texture)
{
g_object_unref (priv->parent_texture);
priv->parent_texture = NULL;
if (was_visible)
clutter_actor_hide (CLUTTER_ACTOR (frame));
}
if (texture)
{
priv->parent_texture = g_object_ref (texture);
if (was_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->parent_texture))
clutter_actor_show (CLUTTER_ACTOR (frame));
}
clutter_actor_queue_relayout (CLUTTER_ACTOR (frame));
g_object_notify (G_OBJECT (frame), "parent-texture");
}
void
tidy_texture_frame_set_frame (TidyTextureFrame *frame,
gfloat top,
gfloat right,
gfloat bottom,
gfloat left)
{
g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame));
tidy_texture_frame_set_frame_internal (frame, top, right, bottom, left);
}
void
tidy_texture_frame_get_frame (TidyTextureFrame *frame,
gfloat *top,
gfloat *right,
gfloat *bottom,
gfloat *left)
{
TidyTextureFramePrivate *priv;
g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame));
priv = frame->priv;
if (top)
*top = priv->top;
if (right)
*right = priv->right;
if (bottom)
*bottom = priv->bottom;
if (left)
*left = priv->left;
}
/**
* tidy_texture_frame_set_needs_paint:
* @frame: a #TidyTextureframe
* @needs_paint: if %FALSE, the paint will be skipped
*
* Provides a hint to the texture frame that it is totally obscured
* and doesn't need to be painted. This would typically be called
* by a parent container if it detects the condition prior to
* painting its children and then unset afterwards.
*
* Since it is not supposed to have any effect on display, it does
* not queue a repaint.
*/
void
tidy_texture_frame_set_needs_paint (TidyTextureFrame *frame,
gboolean needs_paint)
{
TidyTextureFramePrivate *priv;
g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame));
priv = frame->priv;
priv->needs_paint = needs_paint;
}

View File

@@ -1,84 +0,0 @@
/* tidy-texture-frame.h: Expandible texture actor
*
* Copyright (C) 2007, 2008 OpenedHand Ltd
* Copyright (C) 2009 Intel Corp.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef _HAVE_TIDY_TEXTURE_FRAME_H
#define _HAVE_TIDY_TEXTURE_FRAME_H
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define TIDY_TYPE_TEXTURE_FRAME (tidy_texture_frame_get_type ())
#define TIDY_TEXTURE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrame))
#define TIDY_TEXTURE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrameClass))
#define TIDY_IS_TEXTURE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_TEXTURE_FRAME))
#define TIDY_IS_TEXTURE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_TEXTURE_FRAME))
#define TIDY_TEXTURE_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrameClass))
typedef struct _TidyTextureFrame TidyTextureFrame;
typedef struct _TidyTextureFramePrivate TidyTextureFramePrivate;
typedef struct _TidyTextureFrameClass TidyTextureFrameClass;
struct _TidyTextureFrame
{
/*< private >*/
ClutterActor parent_instance;
TidyTextureFramePrivate *priv;
};
struct _TidyTextureFrameClass
{
ClutterActorClass parent_class;
/* padding for future expansion */
void (*_clutter_box_1) (void);
void (*_clutter_box_2) (void);
void (*_clutter_box_3) (void);
void (*_clutter_box_4) (void);
};
GType tidy_texture_frame_get_type (void) G_GNUC_CONST;
ClutterActor * tidy_texture_frame_new (ClutterTexture *texture,
gfloat top,
gfloat right,
gfloat bottom,
gfloat left);
void tidy_texture_frame_set_parent_texture (TidyTextureFrame *frame,
ClutterTexture *texture);
ClutterTexture *tidy_texture_frame_get_parent_texture (TidyTextureFrame *frame);
void tidy_texture_frame_set_frame (TidyTextureFrame *frame,
gfloat top,
gfloat right,
gfloat bottom,
gfloat left);
void tidy_texture_frame_get_frame (TidyTextureFrame *frame,
gfloat *top,
gfloat *right,
gfloat *bottom,
gfloat *left);
void tidy_texture_frame_set_needs_paint (TidyTextureFrame *frame,
gboolean needs_paint);
G_END_DECLS
#endif /* _HAVE_TIDY_TEXTURE_FRAME_H */

View File

@@ -0,0 +1,241 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Find the keycode for the key above the tab key */
/*
* 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
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
/* The standard cycle-windows keybinding should be the key above the
* tab key. This will have a different keysym on different keyboards -
* it's the ` (grave) key on US keyboards but something else on many
* other national layouts. So we need to figure out the keycode for
* this key without reference to key symbol.
*
* The "correct" way to do this is to get the XKB geometry from the
* X server, find the Tab key, find the key above the Tab key in the
* same section and use the keycode for that key. This is what I
* implemented here, but unfortunately, fetching the geometry is rather
* slow (It could take 20ms or more.)
*
* If you looking for a way to optimize Mutter startup performance:
* On all Linux systems using evdev the key above TAB will have
* keycode 49. (KEY_GRAVE=41 + the 8 code point offset between
* evdev keysyms and X keysyms.) So a configure option
* --with-above-tab-keycode=49 could be added that bypassed this
* code. It wouldn't work right for displaying Mutter remotely
* to a non-Linux X server, but that is pretty rare.
*/
#include <config.h>
#include <string.h>
#include "display-private.h"
#include <X11/keysym.h>
#ifdef HAVE_XKB
#include <X11/XKBlib.h>
#include <X11/extensions/XKBgeom.h>
static guint
compute_above_tab_keycode (Display *xdisplay)
{
XkbDescPtr keyboard;
XkbGeometryPtr geometry;
int i, j, k;
int tab_keycode;
char *tab_name;
XkbSectionPtr tab_section;
XkbBoundsRec tab_bounds;
XkbKeyPtr best_key = NULL;
guint best_keycode = (guint)-1;
int best_x_dist = G_MAXINT;
int best_y_dist = G_MAXINT;
/* We need only the Names and the Geometry, but asking for these results
* in the Keyboard information retrieval failing for unknown reasons.
* (Testing with xorg-1.9.1.) So we ask for a part that we don't need
* as well.
*/
keyboard = XkbGetKeyboard (xdisplay,
XkbGBN_ClientSymbolsMask | XkbGBN_KeyNamesMask | XkbGBN_GeometryMask,
XkbUseCoreKbd);
geometry = keyboard->geom;
/* There could potentially be multiple keys with the Tab keysym on the keyboard;
* but XKeysymToKeycode() returns us the one that the alt-Tab binding will
* use which is good enough
*/
tab_keycode = XKeysymToKeycode (xdisplay, XK_Tab);
if (tab_keycode == 0 || tab_keycode < keyboard->min_key_code || tab_keycode > keyboard->max_key_code)
goto out;
/* The keyboard geometry is stored by key "name" rather than keycode.
* (Key names are 4-character strings like like TAB or AE01.) We use the
* 'names' part of the keyboard description to map keycode to key name.
*
* XKB has a "key aliases" feature where a single keyboard key can have
* multiple names (with separate sets of aliases in the 'names' part and
* in the 'geometry' part), but I don't really understand it or how it is used,
* so I'm ignoring it here.
*/
tab_name = keyboard->names->keys[tab_keycode].name; /* Not NULL terminated! */
/* First, iterate through the keyboard geometry to find the tab key; the keyboard
* geometry has a three-level heirarchy of section > row > key
*/
for (i = 0; i < geometry->num_sections; i++)
{
XkbSectionPtr section = &geometry->sections[i];
for (j = 0; j < section->num_rows; j++)
{
int x = 0;
int y = 0;
XkbRowPtr row = &section->rows[j];
for (k = 0; k < row->num_keys; k++)
{
XkbKeyPtr key = &row->keys[k];
XkbShapePtr shape = XkbKeyShape (geometry, key);
if (row->vertical)
y += key->gap;
else
x += key->gap;
if (strncmp (key->name.name, tab_name, XkbKeyNameLength) == 0)
{
tab_section = section;
tab_bounds = shape->bounds;
tab_bounds.x1 += row->left + x;
tab_bounds.x2 += row->left + x;
tab_bounds.y1 += row->top + y;
tab_bounds.y2 += row->top + y;
goto found_tab;
}
if (row->vertical)
y += (shape->bounds.y2 - shape->bounds.y1);
else
x += (shape->bounds.x2 - shape->bounds.x1);
}
}
}
/* No tab key found */
goto out;
found_tab:
/* Now find the key that:
* - Is in the same section as the Tab key
* - Has a horizontal center in the Tab key's horizonal bounds
* - Is above the Tab key at a distance closer than any other key
* - In case of ties, has its horizontal center as close as possible
* to the Tab key's horizontal center
*/
for (j = 0; j < tab_section->num_rows; j++)
{
int x = 0;
int y = 0;
XkbRowPtr row = &tab_section->rows[j];
for (k = 0; k < row->num_keys; k++)
{
XkbKeyPtr key = &row->keys[k];
XkbShapePtr shape = XkbKeyShape(geometry, key);
XkbBoundsRec bounds = shape->bounds;
int x_center;
int x_dist, y_dist;
if (row->vertical)
y += key->gap;
else
x += key->gap;
bounds.x1 += row->left + x;
bounds.x2 += row->left + x;
bounds.y1 += row->top + y;
bounds.y2 += row->top + y;
y_dist = tab_bounds.y1 - bounds.y2;
if (y_dist < 0)
continue;
x_center = (bounds.x1 + bounds.x2) / 2;
if (x_center < tab_bounds.x1 || x_center > tab_bounds.x2)
continue;
x_dist = ABS (x_center - (tab_bounds.x1 + tab_bounds.x2) / 2);
if (y_dist < best_y_dist ||
(y_dist == best_y_dist && x_dist < best_x_dist))
{
best_key = key;
best_x_dist = x_dist;
best_y_dist = y_dist;
}
if (row->vertical)
y += (shape->bounds.y2 - shape->bounds.y1);
else
x += (shape->bounds.x2 - shape->bounds.x1);
}
}
if (best_key == NULL)
goto out;
/* Now we need to resolve the name of the best key back to a keycode */
for (i = keyboard->min_key_code; i < keyboard->max_key_code; i++)
{
if (strncmp (best_key->name.name, keyboard->names->keys[i].name, XkbKeyNameLength) == 0)
{
best_keycode = i;
break;
}
}
out:
XkbFreeKeyboard (keyboard, 0, True);
return best_keycode;
}
#else /* !HAVE_XKB */
static guint
compute_above_tab_keycode (Display *xdisplay)
{
return XKeysymToKeycode (xdisplay, XK_grave);
}
#endif /* HAVE_XKB */
guint
meta_display_get_above_tab_keycode (MetaDisplay *display)
{
if (display->above_tab_keycode == 0) /* not yet computed */
display->above_tab_keycode = compute_above_tab_keycode (display->xdisplay);
if (display->above_tab_keycode == (guint)-1) /* failed to compute */
return 0;
else
return display->above_tab_keycode;
}

View File

@@ -340,7 +340,6 @@ meta_rectangle_resize_with_gravity (const MetaRectangle *old_rect,
*/
/* First, the x direction */
int adjust = 0;
switch (gravity)
{
case NorthWestGravity:
@@ -373,7 +372,6 @@ meta_rectangle_resize_with_gravity (const MetaRectangle *old_rect,
rect->width = new_width;
/* Next, the y direction */
adjust = 0;
switch (gravity)
{
case NorthWestGravity:

View File

@@ -796,7 +796,7 @@ constrain_maximization (MetaWindow *window,
/* Determine whether constraint applies; exit if it doesn't */
if ((!window->maximized_horizontally && !window->maximized_vertically) ||
META_WINDOW_TILED (window))
META_WINDOW_TILED_SIDE_BY_SIDE (window))
return TRUE;
/* Calculate target_size = maximized size of (window + frame) */
@@ -880,7 +880,7 @@ constrain_tiling (MetaWindow *window,
return TRUE;
/* Determine whether constraint applies; exit if it doesn't */
if (!META_WINDOW_TILED (window))
if (!META_WINDOW_TILED_SIDE_BY_SIDE (window))
return TRUE;
/* Calculate target_size - as the tile previews need this as well, we
@@ -968,7 +968,8 @@ constrain_size_increments (MetaWindow *window,
/* Determine whether constraint applies; exit if it doesn't */
if (META_WINDOW_MAXIMIZED (window) || window->fullscreen ||
META_WINDOW_TILED (window) || info->action_type == ACTION_MOVE)
META_WINDOW_TILED_SIDE_BY_SIDE (window) ||
info->action_type == ACTION_MOVE)
return TRUE;
/* Determine whether constraint is already satisfied; exit if it is */
@@ -1099,7 +1100,8 @@ constrain_aspect_ratio (MetaWindow *window,
constraints_are_inconsistent = minr > maxr;
if (constraints_are_inconsistent ||
META_WINDOW_MAXIMIZED (window) || window->fullscreen ||
META_WINDOW_TILED (window) || info->action_type == ACTION_MOVE)
META_WINDOW_TILED_SIDE_BY_SIDE (window) ||
info->action_type == ACTION_MOVE)
return TRUE;
/* Determine whether constraint is already satisfied; exit if it is. We

View File

@@ -117,65 +117,8 @@ meta_core_get (Display *xdisplay,
*((MetaFrameFlags*)answer) = meta_frame_get_flags (window->frame);
break;
case META_CORE_GET_FRAME_TYPE:
{
MetaFrameType base_type = META_FRAME_TYPE_LAST;
switch (window->type)
{
case META_WINDOW_NORMAL:
base_type = META_FRAME_TYPE_NORMAL;
break;
case META_WINDOW_DIALOG:
base_type = META_FRAME_TYPE_DIALOG;
break;
case META_WINDOW_MODAL_DIALOG:
base_type = META_FRAME_TYPE_MODAL_DIALOG;
break;
case META_WINDOW_MENU:
base_type = META_FRAME_TYPE_MENU;
break;
case META_WINDOW_UTILITY:
base_type = META_FRAME_TYPE_UTILITY;
break;
case META_WINDOW_DESKTOP:
case META_WINDOW_DOCK:
case META_WINDOW_TOOLBAR:
case META_WINDOW_SPLASHSCREEN:
case META_WINDOW_DROPDOWN_MENU:
case META_WINDOW_POPUP_MENU:
case META_WINDOW_TOOLTIP:
case META_WINDOW_NOTIFICATION:
case META_WINDOW_COMBO:
case META_WINDOW_DND:
case META_WINDOW_OVERRIDE_OTHER:
/* No frame */
base_type = META_FRAME_TYPE_LAST;
break;
}
if (base_type == META_FRAME_TYPE_LAST)
{
/* can't add border if undecorated */
*((MetaFrameType*)answer) = META_FRAME_TYPE_LAST;
}
else if (window->border_only)
{
/* override base frame type */
*((MetaFrameType*)answer) = META_FRAME_TYPE_BORDER;
}
else
{
*((MetaFrameType*)answer) = base_type;
}
break;
}
*((MetaFrameType*)answer) = meta_window_get_frame_type (window);
break;
case META_CORE_GET_MINI_ICON:
*((GdkPixbuf**)answer) = window->mini_icon;
break;

View File

@@ -77,6 +77,13 @@ typedef enum {
*/
#define N_IGNORED_SERIALS 4
typedef enum {
META_TILE_NONE,
META_TILE_LEFT,
META_TILE_RIGHT,
META_TILE_MAXIMIZED
} MetaTileMode;
struct _MetaDisplay
{
GObject parent_instance;
@@ -179,6 +186,7 @@ struct _MetaDisplay
int grab_anchor_root_x;
int grab_anchor_root_y;
MetaRectangle grab_anchor_window_pos;
MetaTileMode grab_tile_mode;
int grab_latest_motion_x;
int grab_latest_motion_y;
gulong grab_mask;
@@ -221,6 +229,7 @@ struct _MetaDisplay
KeySym *keymap;
int keysyms_per_keycode;
XModifierKeymap *modmap;
unsigned int above_tab_keycode;
unsigned int ignored_modifier_mask;
unsigned int num_lock_mask;
unsigned int scroll_lock_mask;
@@ -433,4 +442,7 @@ void meta_display_remove_autoraise_callback (MetaDisplay *display);
void meta_display_overlay_key_activate (MetaDisplay *display);
/* In above-tab-keycode.c */
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
#endif

View File

@@ -387,26 +387,6 @@ enable_compositor (MetaDisplay *display,
}
}
static void
disable_compositor (MetaDisplay *display)
{
GSList *list;
if (!display->compositor)
return;
for (list = display->screens; list != NULL; list = list->next)
{
MetaScreen *screen = list->data;
meta_compositor_unmanage_screen (screen->display->compositor,
screen);
}
meta_compositor_destroy (display->compositor);
display->compositor = NULL;
}
static void
meta_display_init (MetaDisplay *disp)
{
@@ -573,6 +553,7 @@ meta_display_open (void)
the_display->grab_window = NULL;
the_display->grab_screen = NULL;
the_display->grab_resize_popup = NULL;
the_display->grab_tile_mode = META_TILE_NONE;
the_display->grab_edge_resistance_data = NULL;
@@ -839,8 +820,7 @@ meta_display_open (void)
/* We don't composite the windows here because they will be composited
faster with the call to meta_screen_manage_all_windows further down
the code */
if (1) /* meta_prefs_get_compositing_manager ()) FIXME */
enable_compositor (the_display, FALSE);
enable_compositor (the_display, FALSE);
meta_display_grab (the_display);
@@ -2642,6 +2622,10 @@ event_callback (XEvent *event,
meta_bell_notify (display, xkb_ev);
}
break;
case XkbNewKeyboardNotify:
case XkbMapNotify:
meta_display_process_mapping_event (display, event);
break;
}
}
#endif
@@ -3597,6 +3581,10 @@ meta_display_begin_grab_op (MetaDisplay *display,
display->grab_xwindow = grab_xwindow;
display->grab_button = button;
display->grab_mask = modmask;
if (window)
display->grab_tile_mode = window->tile_mode;
else
display->grab_tile_mode = META_TILE_NONE;
display->grab_anchor_root_x = root_x;
display->grab_anchor_root_y = root_y;
display->grab_latest_motion_x = root_x;
@@ -3793,6 +3781,7 @@ meta_display_end_grab_op (MetaDisplay *display,
display->grab_window = NULL;
display->grab_screen = NULL;
display->grab_xwindow = None;
display->grab_tile_mode = META_TILE_NONE;
display->grab_op = META_GRAB_OP_NONE;
if (display->grab_resize_popup)
@@ -5184,15 +5173,6 @@ prefs_changed_callback (MetaPreference pref,
{
meta_bell_set_audible (display, meta_prefs_bell_is_audible ());
}
else if (pref == META_PREF_COMPOSITING_MANAGER)
{
gboolean cm = meta_prefs_get_compositing_manager ();
if (cm)
enable_compositor (display, TRUE);
else
disable_compositor (display);
}
else if (pref == META_PREF_ATTACH_MODAL_DIALOGS)
{
MetaDisplay *display = data;

View File

@@ -291,6 +291,12 @@ meta_frame_get_flags (MetaFrame *frame)
if (META_WINDOW_MAXIMIZED (frame->window))
flags |= META_FRAME_MAXIMIZED;
if (META_WINDOW_TILED_LEFT (frame->window))
flags |= META_FRAME_TILED_LEFT;
if (META_WINDOW_TILED_RIGHT (frame->window))
flags |= META_FRAME_TILED_RIGHT;
if (frame->window->fullscreen)
flags |= META_FRAME_FULLSCREEN;

View File

@@ -117,6 +117,10 @@ reload_keymap (MetaDisplay *display)
if (display->keymap)
meta_XFree (display->keymap);
/* This is expensive to compute, so we'll lazily load if and when we first
* need it */
display->above_tab_keycode = 0;
display->keymap = XGetKeyboardMapping (display->xdisplay,
display->min_keycode,
display->max_keycode -
@@ -228,17 +232,26 @@ reload_modmap (MetaDisplay *display)
display->meta_mask);
}
static guint
keysym_to_keycode (MetaDisplay *display,
guint keysym)
{
if (keysym == META_KEY_ABOVE_TAB)
return meta_display_get_above_tab_keycode (display);
else
return XKeysymToKeycode (display->xdisplay, keysym);
}
static void
reload_keycodes (MetaDisplay *display)
{
meta_topic (META_DEBUG_KEYBINDINGS,
"Reloading keycodes for binding tables\n");
if (display->overlay_key_combo.keysym
&& display->overlay_key_combo.keycode == 0)
if (display->overlay_key_combo.keysym != 0)
{
display->overlay_key_combo.keycode = XKeysymToKeycode (
display->xdisplay, display->overlay_key_combo.keysym);
display->overlay_key_combo.keycode =
keysym_to_keycode (display, display->overlay_key_combo.keysym);
}
if (display->key_bindings)
@@ -248,9 +261,11 @@ reload_keycodes (MetaDisplay *display)
i = 0;
while (i < display->n_key_bindings)
{
if (display->key_bindings[i].keycode == 0)
display->key_bindings[i].keycode = XKeysymToKeycode (
display->xdisplay, display->key_bindings[i].keysym);
if (display->key_bindings[i].keysym != 0)
{
display->key_bindings[i].keycode =
keysym_to_keycode (display, display->key_bindings[i].keysym);
}
++i;
}
@@ -520,6 +535,9 @@ meta_display_get_keybinding_action (MetaDisplay *display,
mask = mask & 0xff & ~display->ignored_modifier_mask;
binding = display_get_keybinding (display, keysym, keycode, mask);
if (!binding && keycode == meta_display_get_above_tab_keycode (display))
binding = display_get_keybinding (display, META_KEY_ABOVE_TAB, keycode, mask);
if (binding)
return meta_prefs_get_keybinding_action (binding->name);
else
@@ -530,26 +548,51 @@ void
meta_display_process_mapping_event (MetaDisplay *display,
XEvent *event)
{
gboolean keymap_changed = FALSE;
gboolean modmap_changed = FALSE;
#ifdef HAVE_XKB
if (event->type == display->xkb_base_event_type)
{
meta_topic (META_DEBUG_KEYBINDINGS,
"XKB mapping changed, will redo keybindings\n");
keymap_changed = TRUE;
modmap_changed = TRUE;
}
else
#endif
if (event->xmapping.request == MappingModifier)
{
meta_topic (META_DEBUG_KEYBINDINGS,
"Received MappingModifier event, will reload modmap and redo keybindings\n");
reload_modmap (display);
reload_modifiers (display);
regrab_key_bindings (display);
modmap_changed = TRUE;
}
else if (event->xmapping.request == MappingKeyboard)
{
meta_topic (META_DEBUG_KEYBINDINGS,
"Received MappingKeyboard event, will reload keycodes and redo keybindings\n");
reload_keymap (display);
keymap_changed = TRUE;
}
/* Now to do the work itself */
if (keymap_changed || modmap_changed)
{
if (keymap_changed)
reload_keymap (display);
/* Deciphering the modmap depends on the loaded keysyms to find out
* what modifiers is Super and so forth, so we need to reload it
* even when only the keymap changes */
reload_modmap (display);
reload_keycodes (display);
if (keymap_changed)
reload_keycodes (display);
reload_modifiers (display);
regrab_key_bindings (display);
}
@@ -617,6 +660,14 @@ meta_display_init_keys (MetaDisplay *display)
/* Keys are actually grabbed in meta_screen_grab_keys() */
meta_prefs_add_listener (bindings_changed_callback, display);
#ifdef HAVE_XKB
/* meta_display_init_keys() should have already called XkbQueryExtension() */
if (display->xkb_base_event_type != -1)
XkbSelectEvents (display->xdisplay, XkbUseCoreKbd,
XkbNewKeyboardNotifyMask | XkbMapNotifyMask,
XkbNewKeyboardNotifyMask | XkbMapNotifyMask);
#endif
}
void
@@ -1500,15 +1551,24 @@ process_mouse_move_resize_grab (MetaDisplay *display,
if (keysym == XK_Escape)
{
/* Hide the tiling preview if necessary */
if (window->tile_mode != META_TILE_NONE)
meta_screen_tile_preview_hide (screen);
/* Restore the original tile mode */
window->tile_mode = display->grab_tile_mode;
/* End move or resize and restore to original state. If the
* window was a maximized window that had been "shaken loose" we
* need to remaximize it. In normal cases, we need to do a
* moveresize now to get the position back to the original.
*/
if (window->shaken_loose)
if (window->shaken_loose || window->tile_mode == META_TILE_MAXIMIZED)
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL |
META_MAXIMIZE_VERTICAL);
else if (window->tile_mode != META_TILE_NONE)
meta_window_tile (window);
else
meta_window_move_resize (display->grab_window,
TRUE,

View File

@@ -296,18 +296,6 @@ meta_parse_options (int *argc, char ***argv,
N_("Make X calls synchronous"),
NULL
},
{
"composite", 'c', COMPOSITE_OPTS_FLAGS, G_OPTION_ARG_NONE,
&my_args.composite,
N_("Turn compositing on"),
NULL
},
{
"no-composite", 0, COMPOSITE_OPTS_FLAGS, G_OPTION_ARG_NONE,
&my_args.no_composite,
N_("Turn compositing off"),
NULL
},
{
"no-force-fullscreen", 0, COMPOSITE_OPTS_FLAGS, G_OPTION_ARG_NONE,
&my_args.no_force_fullscreen,
@@ -454,7 +442,7 @@ sigterm_handler (int signum)
{
if (sigterm_pipe_fds[1] >= 0)
{
int dummy;
int G_GNUC_UNUSED dummy;
dummy = write (sigterm_pipe_fds[1], "", 1);
close (sigterm_pipe_fds[1]);
@@ -705,9 +693,6 @@ main (int argc, char **argv)
g_free (meta_args.display_name);
g_free (meta_args.client_id);
if (meta_args.composite || meta_args.no_composite)
meta_prefs_set_compositing_manager (meta_args.composite);
if (meta_args.no_force_fullscreen)
meta_prefs_set_force_fullscreen (FALSE);

View File

@@ -50,7 +50,6 @@
*/
#define KEY_TITLEBAR_FONT "/apps/metacity/general/titlebar_font"
#define KEY_NUM_WORKSPACES "/apps/metacity/general/num_workspaces"
#define KEY_COMPOSITOR "/apps/metacity/general/compositing_manager"
#define KEY_GNOME_ACCESSIBILITY "/desktop/gnome/interface/accessibility"
#define KEY_COMMAND_DIRECTORY "/apps/metacity/keybinding_commands"
@@ -102,9 +101,8 @@ static gboolean gnome_accessibility = FALSE;
static gboolean gnome_animations = TRUE;
static char *cursor_theme = NULL;
static int cursor_size = 24;
static gboolean compositing_manager = FALSE;
static gboolean resize_with_right_button = FALSE;
static gboolean side_by_side_tiling = FALSE;
static gboolean edge_tiling = FALSE;
static gboolean force_fullscreen = TRUE;
static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_FULLSCREEN_FLASH;
@@ -413,19 +411,14 @@ static MetaBoolPreference preferences_bool[] =
&gnome_animations,
TRUE,
},
{ "/apps/metacity/general/compositing_manager",
META_PREF_COMPOSITING_MANAGER,
&compositing_manager,
FALSE,
},
{ "/apps/metacity/general/resize_with_right_button",
META_PREF_RESIZE_WITH_RIGHT_BUTTON,
&resize_with_right_button,
FALSE,
},
{ "/apps/metacity/general/side_by_side_tiling",
META_PREF_SIDE_BY_SIDE_TILING,
&side_by_side_tiling,
{ "/apps/metacity/general/edge_tiling",
META_PREF_EDGE_TILING,
&edge_tiling,
FALSE,
},
{ "/apps/mutter/general/live_hidden_windows",
@@ -2004,14 +1997,11 @@ meta_preference_to_string (MetaPreference pref)
case META_PREF_CURSOR_SIZE:
return "CURSOR_SIZE";
case META_PREF_COMPOSITING_MANAGER:
return "COMPOSITING_MANAGER";
case META_PREF_RESIZE_WITH_RIGHT_BUTTON:
return "RESIZE_WITH_RIGHT_BUTTON";
case META_PREF_SIDE_BY_SIDE_TILING:
return "SIDE_BY_SIDE_TILING";
case META_PREF_EDGE_TILING:
return "EDGE_TILING";
case META_PREF_FORCE_FULLSCREEN:
return "FORCE_FULLSCREEN";
@@ -2926,9 +2916,9 @@ meta_prefs_get_gnome_animations ()
}
gboolean
meta_prefs_get_side_by_side_tiling ()
meta_prefs_get_edge_tiling ()
{
return side_by_side_tiling;
return edge_tiling;
}
MetaKeyBindingAction
@@ -2992,12 +2982,6 @@ meta_prefs_get_window_binding (const char *name,
g_assert_not_reached ();
}
gboolean
meta_prefs_get_compositing_manager (void)
{
return compositing_manager;
}
guint
meta_prefs_get_mouse_button_resize (void)
{
@@ -3016,28 +3000,6 @@ meta_prefs_get_force_fullscreen (void)
return force_fullscreen;
}
void
meta_prefs_set_compositing_manager (gboolean whether)
{
#ifdef HAVE_GCONF
GError *err = NULL;
gconf_client_set_bool (default_client,
KEY_COMPOSITOR,
whether,
&err);
if (err)
{
meta_warning (_("Error setting compositor status: %s\n"),
err->message);
g_error_free (err);
}
#else
compositing_manager = whether;
#endif
}
/**
* meta_prefs_get_clutter_plugins:
*

View File

@@ -50,14 +50,6 @@ struct _MetaMonitorInfo
typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
gpointer user_data);
typedef enum
{
META_SCREEN_TOPLEFT,
META_SCREEN_TOPRIGHT,
META_SCREEN_BOTTOMLEFT,
META_SCREEN_BOTTOMRIGHT
} MetaScreenCorner;
typedef enum
{
META_SCREEN_UP,
@@ -127,6 +119,7 @@ struct _MetaScreen
int columns_of_workspaces;
MetaScreenCorner starting_corner;
guint vertical_workspaces : 1;
guint workspace_layout_overridden : 1;
guint keys_grabbed : 1;
guint all_keys_grabbed : 1;
@@ -184,6 +177,7 @@ void meta_screen_workspace_popup_destroy (MetaScreen *screen);
void meta_screen_tile_preview_update (MetaScreen *screen,
gboolean delay);
void meta_screen_tile_preview_hide (MetaScreen *screen);
MetaWindow* meta_screen_get_mouse_window (MetaScreen *screen,
MetaWindow *not_this_one);
@@ -254,4 +248,6 @@ void meta_screen_workspace_switched (MetaScreen *screen,
int to,
MetaMotionDirection direction);
void meta_screen_set_active_workspace_hint (MetaScreen *screen);
#endif

View File

@@ -951,11 +951,10 @@ meta_screen_manage_all_windows (MetaScreen *screen)
for (list = windows; list != NULL; list = list->next)
{
WindowInfo *info = list->data;
MetaWindow *window;
window = meta_window_new_with_attrs (screen->display, info->xwindow, TRUE,
META_COMP_EFFECT_NONE,
&info->attrs);
meta_window_new_with_attrs (screen->display, info->xwindow, TRUE,
META_COMP_EFFECT_NONE,
&info->attrs);
}
meta_stack_thaw (screen->stack);
@@ -978,7 +977,15 @@ meta_screen_composite_all_windows (MetaScreen *screen)
windows = meta_display_list_windows (display,
META_LIST_INCLUDE_OVERRIDE_REDIRECT);
for (tmp = windows; tmp != NULL; tmp = tmp->next)
meta_compositor_add_window (display->compositor, tmp->data);
{
MetaWindow *window = tmp->data;
meta_compositor_add_window (display->compositor, window);
if (window->visible_to_compositor)
meta_compositor_show_window (display->compositor, window,
META_COMP_EFFECT_NONE);
}
g_slist_free (windows);
/* initialize the compositor's view of the stacking order */
@@ -1276,6 +1283,7 @@ meta_screen_remove_workspace (MetaScreen *screen, MetaWorkspace *workspace,
MetaWorkspace *neighbour = NULL;
GList *next = NULL;
int index;
gboolean active_index_changed;
int new_num;
l = screen->workspaces;
@@ -1314,6 +1322,7 @@ meta_screen_remove_workspace (MetaScreen *screen, MetaWorkspace *workspace,
/* To emit the signal after removing the workspace */
index = meta_workspace_index (workspace);
active_index_changed = index < meta_screen_get_active_workspace_index (screen);
/* This also removes the workspace from the screens list */
meta_workspace_remove (workspace);
@@ -1323,6 +1332,11 @@ meta_screen_remove_workspace (MetaScreen *screen, MetaWorkspace *workspace,
set_number_of_spaces_hint (screen, new_num);
meta_prefs_set_num_workspaces (new_num);
/* If deleting a workspace before the current workspace, the active
* workspace index changes, so we need to update that hint */
if (active_index_changed)
meta_screen_set_active_workspace_hint (workspace->screen);
l = next;
while (l)
{
@@ -1758,6 +1772,7 @@ meta_screen_tile_preview_update_timeout (gpointer data)
MetaScreen *screen = data;
MetaWindow *window = screen->display->grab_window;
gboolean composited = screen->display->compositor != NULL;
gboolean needs_preview = FALSE;
screen->tile_preview_timeout_id = 0;
@@ -1775,9 +1790,28 @@ meta_screen_tile_preview_update_timeout (gpointer data)
create_serial);
}
if (window
&& !META_WINDOW_TILED (window)
&& window->tile_mode != META_TILE_NONE)
if (window)
{
switch (window->tile_mode)
{
case META_TILE_LEFT:
case META_TILE_RIGHT:
if (!META_WINDOW_TILED_SIDE_BY_SIDE (window))
needs_preview = TRUE;
break;
case META_TILE_MAXIMIZED:
if (!META_WINDOW_MAXIMIZED (window))
needs_preview = TRUE;
break;
default:
needs_preview = FALSE;
break;
}
}
if (needs_preview)
{
MetaRectangle tile_rect;
@@ -1815,6 +1849,16 @@ meta_screen_tile_preview_update (MetaScreen *screen,
}
}
void
meta_screen_tile_preview_hide (MetaScreen *screen)
{
if (screen->tile_preview_timeout_id > 0)
g_source_remove (screen->tile_preview_timeout_id);
if (screen->tile_preview)
meta_tile_preview_hide (screen->tile_preview);
}
MetaWindow*
meta_screen_get_mouse_window (MetaScreen *screen,
MetaWindow *not_this_one)
@@ -2119,6 +2163,9 @@ meta_screen_update_workspace_layout (MetaScreen *screen)
{
gulong *list;
int n_items;
if (screen->workspace_layout_overridden)
return;
list = NULL;
n_items = 0;
@@ -2205,6 +2252,43 @@ meta_screen_update_workspace_layout (MetaScreen *screen)
screen->starting_corner);
}
/**
* meta_screen_override_workspace_layout:
* @screen: a #MetaScreen
* @starting_corner: the corner at which the first workspace is found
* @vertical_layout: if %TRUE the workspaces are laid out in columns rather than rows
* @n_rows: number of rows of workspaces, or -1 to determine the number of rows from
* @n_columns and the total number of workspaces
* @n_columns: number of columns of workspaces, or -1 to determine the number of columns from
* @n_rows and the total number of workspaces
*
* Explicitly set the layout of workspaces. Once this has been called, the contents of the
* _NET_DESKTOP_LAYOUT property on the root window are completely ignored.
*/
void
meta_screen_override_workspace_layout (MetaScreen *screen,
MetaScreenCorner starting_corner,
gboolean vertical_layout,
int n_rows,
int n_columns)
{
g_return_if_fail (META_IS_SCREEN (screen));
g_return_if_fail (n_rows > 0 || n_columns > 0);
g_return_if_fail (n_rows != 0 && n_columns != 0);
screen->workspace_layout_overridden = TRUE;
screen->vertical_workspaces = vertical_layout != FALSE;
screen->starting_corner = starting_corner;
screen->rows_of_workspaces = n_rows;
screen->columns_of_workspaces = n_columns;
/* In theory we should remove _NET_DESKTOP_LAYOUT from _NET_SUPPORTED at this
* point, but it's unlikely that anybody checks that, and it's unlikely that
* anybody who checks that handles changes, so we'd probably just create
* a race condition. And it's hard to implement with the code in set_supported_hint()
*/
}
static void
set_workspace_names (MetaScreen *screen)
{
@@ -3308,3 +3392,29 @@ meta_screen_workspace_switched (MetaScreen *screen,
from, to, direction);
}
void
meta_screen_set_active_workspace_hint (MetaScreen *screen)
{
unsigned long data[1];
/* this is because we destroy the spaces in order,
* so we always end up setting a current desktop of
* 0 when closing a screen, so lose the current desktop
* on restart. By doing this we keep the current
* desktop on restart.
*/
if (screen->closing > 0)
return;
data[0] = meta_workspace_index (screen->active_workspace);
meta_verbose ("Setting _NET_CURRENT_DESKTOP to %lu\n", data[0]);
meta_error_trap_push (screen->display);
XChangeProperty (screen->display->xdisplay, screen->xroot,
screen->display->atom__NET_CURRENT_DESKTOP,
XA_CARDINAL,
32, PropModeReplace, (guchar*) data, 1);
meta_error_trap_pop (screen->display);
}

View File

@@ -54,8 +54,8 @@
*
* When we receive a new event: a) we compare the serial in the event to
* the serial of the queued requests and remove any that are now
* no longer pending b) drop the predicted stacking order to recompute
* it at the next opportunity.
* no longer pending b) if necessary, drop the predicted stacking
* order to recompute it at the next opportunity.
*
* Possible optimizations:
* Keep the stacks as an array + reverse-mapping hash table to avoid
@@ -505,6 +505,8 @@ static void
stack_tracker_event_received (MetaStackTracker *tracker,
MetaStackOp *op)
{
gboolean need_sync = FALSE;
meta_stack_op_dump (op, "Stack op event received: ", "\n");
if (op->any.serial < tracker->server_serial)
@@ -512,7 +514,8 @@ stack_tracker_event_received (MetaStackTracker *tracker,
tracker->server_serial = op->any.serial;
meta_stack_op_apply (op, tracker->server_stack);
if (meta_stack_op_apply (op, tracker->server_stack))
need_sync = TRUE;
while (tracker->queued_requests->head)
{
@@ -522,17 +525,21 @@ stack_tracker_event_received (MetaStackTracker *tracker,
g_queue_pop_head (tracker->queued_requests);
meta_stack_op_free (queued_op);
need_sync = TRUE;
}
if (tracker->predicted_stack)
if (need_sync)
{
g_array_free (tracker->predicted_stack, TRUE);
tracker->predicted_stack = NULL;
if (tracker->predicted_stack)
{
g_array_free (tracker->predicted_stack, TRUE);
tracker->predicted_stack = NULL;
}
meta_stack_tracker_queue_sync_stack (tracker);
}
meta_stack_tracker_dump (tracker);
meta_stack_tracker_queue_sync_stack (tracker);
}
void

View File

@@ -416,7 +416,6 @@ run_speed_comparison (Display *xdisplay,
while ((task = ag_get_next_completed_task (xdisplay)))
{
int result;
Atom actual_type;
int actual_format;
unsigned long n_items;
@@ -426,12 +425,12 @@ run_speed_comparison (Display *xdisplay,
assert (ag_task_have_reply (task));
data = NULL;
result = ag_task_get_reply_and_free (task,
&actual_type,
&actual_format,
&n_items,
&bytes_after,
&data);
ag_task_get_reply_and_free (task,
&actual_type,
&actual_format,
&n_items,
&bytes_after,
&data);
if (data)
XFree (data);

View File

@@ -61,12 +61,6 @@ typedef enum {
#define NUMBER_OF_QUEUES 3
typedef enum {
META_TILE_NONE,
META_TILE_LEFT,
META_TILE_RIGHT
} MetaTileMode;
struct _MetaWindow
{
GObject parent_instance;
@@ -409,11 +403,15 @@ struct _MetaWindowClass
(w)->maximized_vertically)
#define META_WINDOW_MAXIMIZED_VERTICALLY(w) ((w)->maximized_vertically)
#define META_WINDOW_MAXIMIZED_HORIZONTALLY(w) ((w)->maximized_horizontally)
#define META_WINDOW_TILED(w) ((w)->maximized_vertically && \
!(w)->maximized_horizontally && \
(w)->tile_mode != META_TILE_NONE)
#define META_WINDOW_TILED_SIDE_BY_SIDE(w) ((w)->maximized_vertically && \
!(w)->maximized_horizontally && \
(w)->tile_mode != META_TILE_NONE)
#define META_WINDOW_TILED_LEFT(w) (META_WINDOW_TILED_SIDE_BY_SIDE(w) && \
(w)->tile_mode == META_TILE_LEFT)
#define META_WINDOW_TILED_RIGHT(w) (META_WINDOW_TILED_SIDE_BY_SIDE(w) && \
(w)->tile_mode == META_TILE_RIGHT)
#define META_WINDOW_ALLOWS_MOVE(w) ((w)->has_move_func && !(w)->fullscreen)
#define META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS(w) ((w)->has_resize_func && !META_WINDOW_MAXIMIZED (w) && !META_WINDOW_TILED(w) && !(w)->fullscreen && !(w)->shaded)
#define META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS(w) ((w)->has_resize_func && !META_WINDOW_MAXIMIZED (w) && !META_WINDOW_TILED_SIDE_BY_SIDE(w) && !(w)->fullscreen && !(w)->shaded)
#define META_WINDOW_ALLOWS_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && \
(((w)->size_hints.min_width < (w)->size_hints.max_width) || \
((w)->size_hints.min_height < (w)->size_hints.max_height)))
@@ -433,6 +431,7 @@ void meta_window_unmanage (MetaWindow *window,
void meta_window_calc_showing (MetaWindow *window);
void meta_window_queue (MetaWindow *window,
guint queuebits);
void meta_window_tile (MetaWindow *window);
void meta_window_maximize_internal (MetaWindow *window,
MetaMaximizeFlags directions,
MetaRectangle *saved_rect);
@@ -461,8 +460,6 @@ void meta_window_update_fullscreen_monitors (MetaWindow *window,
unsigned long left,
unsigned long right);
gboolean meta_window_appears_focused (MetaWindow *window);
/* args to move are window pos, not frame pos */
void meta_window_move (MetaWindow *window,
gboolean user_op,

View File

@@ -2678,6 +2678,8 @@ meta_window_show (MetaWindow *window)
if (!window->visible_to_compositor)
{
window->visible_to_compositor = TRUE;
if (window->display->compositor)
{
MetaCompEffect effect = META_COMP_EFFECT_NONE;
@@ -2697,8 +2699,6 @@ meta_window_show (MetaWindow *window)
meta_compositor_show_window (window->display->compositor,
window, effect);
}
window->visible_to_compositor = TRUE;
}
/* We don't want to worry about all cases from inside
@@ -2769,6 +2769,8 @@ meta_window_hide (MetaWindow *window)
if (window->visible_to_compositor)
{
window->visible_to_compositor = FALSE;
if (window->display->compositor)
{
MetaCompEffect effect = META_COMP_EFFECT_NONE;
@@ -2788,8 +2790,6 @@ meta_window_hide (MetaWindow *window)
meta_compositor_hide_window (window->display->compositor,
window, effect);
}
window->visible_to_compositor = FALSE;
}
did_hide = FALSE;
@@ -2972,7 +2972,7 @@ ensure_size_hints_satisfied (MetaRectangle *rect,
static void
meta_window_save_rect (MetaWindow *window)
{
if (!(META_WINDOW_MAXIMIZED (window) || META_WINDOW_TILED (window) || window->fullscreen))
if (!(META_WINDOW_MAXIMIZED (window) || META_WINDOW_TILED_SIDE_BY_SIDE (window) || window->fullscreen))
{
/* save size/pos as appropriate args for move_resize */
if (!window->maximized_horizontally)
@@ -3014,7 +3014,7 @@ force_save_user_window_placement (MetaWindow *window)
static void
save_user_window_placement (MetaWindow *window)
{
if (!(META_WINDOW_MAXIMIZED (window) || META_WINDOW_TILED (window) || window->fullscreen))
if (!(META_WINDOW_MAXIMIZED (window) || META_WINDOW_TILED_SIDE_BY_SIDE (window) || window->fullscreen))
{
MetaRectangle user_rect;
@@ -3158,14 +3158,47 @@ meta_window_maximize (MetaWindow *window,
}
}
static void
/**
* meta_window_get_maximized:
*
* Gets the current maximization state of the window, as combination
* of the %META_MAXIMIZE_HORIZONTAL and %META_MAXIMIZE_VERTICAL flags;
*
* Return value: current maximization state
*/
MetaMaximizeFlags
meta_window_get_maximized (MetaWindow *window)
{
return ((window->maximized_horizontally ? META_MAXIMIZE_HORIZONTAL : 0) |
(window->maximized_vertically ? META_MAXIMIZE_VERTICAL : 0));
}
/**
* meta_window_is_fullscreen:
*
* Return value: %TRUE if the window is currently fullscreen
*/
gboolean
meta_window_is_fullscreen (MetaWindow *window)
{
return window->fullscreen;
}
void
meta_window_tile (MetaWindow *window)
{
MetaMaximizeFlags directions;
/* Don't do anything if no tiling is requested */
if (window->tile_mode == META_TILE_NONE)
return;
meta_window_maximize_internal (window, META_MAXIMIZE_VERTICAL, NULL);
if (window->tile_mode == META_TILE_MAXIMIZED)
directions = META_MAXIMIZE_VERTICAL | META_MAXIMIZE_HORIZONTAL;
else
directions = META_MAXIMIZE_VERTICAL;
meta_window_maximize_internal (window, directions, NULL);
meta_screen_tile_preview_update (window->screen, FALSE);
if (window->display->compositor)
@@ -3192,7 +3225,7 @@ meta_window_tile (MetaWindow *window)
}
static gboolean
meta_window_can_tile (MetaWindow *window)
meta_window_can_tile_side_by_side (MetaWindow *window)
{
const MetaMonitorInfo *monitor;
MetaRectangle tile_area;
@@ -3223,6 +3256,18 @@ meta_window_can_tile (MetaWindow *window)
tile_area.height >= window->size_hints.min_height;
}
static gboolean
meta_window_can_tile_maximized (MetaWindow *window)
{
if (!META_WINDOW_ALLOWS_RESIZE (window))
return FALSE;
if (!window->has_maximize_func)
return FALSE;
return TRUE;
}
static void
unmaximize_window_before_freeing (MetaWindow *window)
{
@@ -3290,6 +3335,13 @@ meta_window_unmaximize_internal (MetaWindow *window,
window->maximized_vertically =
window->maximized_vertically && !unmaximize_vertically;
/* Reset the tile mode for maximized tiled windows for consistency
* with "normal" maximized windows, but keep other tile modes,
* as side-by-side tiled windows may snap back.
*/
if (window->tile_mode == META_TILE_MAXIMIZED)
window->tile_mode = META_TILE_NONE;
/* Unmaximize to the saved_rect position in the direction(s)
* being unmaximized.
*/
@@ -3373,7 +3425,8 @@ meta_window_unmaximize (MetaWindow *window,
MetaMaximizeFlags directions)
{
/* Restore tiling if necessary */
if (window->tile_mode != META_TILE_NONE)
if (window->tile_mode == META_TILE_LEFT ||
window->tile_mode == META_TILE_RIGHT)
{
window->maximized_horizontally = FALSE;
meta_window_tile (window);
@@ -4665,6 +4718,13 @@ meta_window_get_geometry (MetaWindow *window,
window->size_hints.height_inc;
}
/**
* meta_window_get_outer_rect:
* @window: a #MetaWindow
* @rect: (out): pointer to an allocated #MetaRectangle
*
* Gets the rectangle that bounds @window and, if decorated, its decorations.
*/
void
meta_window_get_outer_rect (const MetaWindow *window,
MetaRectangle *rect)
@@ -5910,12 +5970,12 @@ meta_window_client_message (MetaWindow *window,
else if (event->xclient.message_type ==
display->atom__NET_MOVERESIZE_WINDOW)
{
int gravity, source;
int gravity;
guint value_mask;
gravity = (event->xclient.data.l[0] & 0xff);
value_mask = (event->xclient.data.l[0] & 0xf00) >> 8;
source = (event->xclient.data.l[0] & 0xf000) >> 12;
/* source = (event->xclient.data.l[0] & 0xf000) >> 12; */
if (gravity == 0)
gravity = window->size_hints.win_gravity;
@@ -5958,7 +6018,6 @@ meta_window_client_message (MetaWindow *window,
else if (event->xclient.message_type ==
display->atom__NET_WM_FULLSCREEN_MONITORS)
{
MetaClientType source_indication;
gulong top, bottom, left, right;
meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n",
@@ -5968,7 +6027,7 @@ meta_window_client_message (MetaWindow *window,
bottom = event->xclient.data.l[1];
left = event->xclient.data.l[2];
right = event->xclient.data.l[3];
source_indication = event->xclient.data.l[4];
/* source_indication = event->xclient.data.l[4]; */
meta_window_update_fullscreen_monitors (window, top, bottom, left, right);
}
@@ -7578,7 +7637,6 @@ meta_window_titlebar_is_onscreen (MetaWindow *window)
{
MetaRectangle titlebar_rect;
GList *onscreen_region;
int titlebar_size;
gboolean is_onscreen;
const int min_height_needed = 8;
@@ -7592,7 +7650,6 @@ meta_window_titlebar_is_onscreen (MetaWindow *window)
/* Get the rectangle corresponding to the titlebar */
meta_window_get_outer_rect (window, &titlebar_rect);
titlebar_rect.height = window->frame->child_y;
titlebar_size = meta_rectangle_area (&titlebar_rect);
/* Run through the spanning rectangles for the screen and see if one of
* them overlaps with the titlebar sufficiently to consider it onscreen.
@@ -7766,14 +7823,13 @@ update_move (MetaWindow *window,
shake_threshold = meta_ui_get_drag_threshold (window->screen->ui) *
DRAG_THRESHOLD_TO_SHAKE_THRESHOLD_FACTOR;
if (meta_prefs_get_side_by_side_tiling () &&
meta_window_can_tile (window))
if (meta_prefs_get_edge_tiling ())
{
const MetaMonitorInfo *monitor;
MetaRectangle work_area;
/* For tiling we are interested in the work area of the monitor where
* the pointer is located.
/* For side-by-side tiling we are interested in the inside vertical
* edges of the work area of the monitor where the pointer is located.
* Also see comment in meta_window_get_current_tile_area()
*/
monitor = meta_screen_get_current_monitor (window->screen);
@@ -7781,17 +7837,38 @@ update_move (MetaWindow *window,
monitor->number,
&work_area);
if (y >= monitor->rect.y &&
y < (monitor->rect.y + monitor->rect.height))
if (meta_window_can_tile_side_by_side (window))
{
/* check if cursor is near an edge of the work area */
if (x >= monitor->rect.x && x < (work_area.x + shake_threshold))
window->tile_mode = META_TILE_LEFT;
else if (x >= work_area.x + work_area.width - shake_threshold &&
x < (monitor->rect.x + monitor->rect.width))
window->tile_mode = META_TILE_RIGHT;
else
window->tile_mode = META_TILE_NONE;
if (y >= monitor->rect.y &&
y < (monitor->rect.y + monitor->rect.height))
{
/* check if cursor is near an edge of the work area */
if (x >= monitor->rect.x && x < (work_area.x + shake_threshold))
window->tile_mode = META_TILE_LEFT;
else if (x >= work_area.x + work_area.width - shake_threshold &&
x < (monitor->rect.x + monitor->rect.width))
window->tile_mode = META_TILE_RIGHT;
else
window->tile_mode = META_TILE_NONE;
}
}
/* For maximized tiling we are interested in the outside top edge
* of the work area of the monitor where the pointer is located.
*
* We use the outside edge instead of the inside edge, because we
* don't want to force users to maximize windows they are placing
* near the top of their screens.
*/
if (meta_window_can_tile_maximized (window))
{
if (x >= monitor->rect.x &&
x < (monitor->rect.x + monitor->rect.width))
{
/* check if cursor is on the top edge of the monitor*/
if (y >= monitor->rect.y && y <= work_area.y)
window->tile_mode = META_TILE_MAXIMIZED;
}
}
}
@@ -7801,12 +7878,15 @@ update_move (MetaWindow *window,
*/
if ((META_WINDOW_MAXIMIZED (window) && ABS (dy) >= shake_threshold) ||
(META_WINDOW_TILED (window) && (MAX (ABS (dx), ABS (dy)) >= shake_threshold)))
(META_WINDOW_TILED_SIDE_BY_SIDE (window) && (MAX (ABS (dx), ABS (dy)) >= shake_threshold)))
{
double prop;
/* Shake loose */
window->shaken_loose = !META_WINDOW_TILED (window);
/* Shake loose, so that the window snaps back to maximized
* when dragged near the top; do not snap back if tiling
* is enabled, as top edge tiling can be used in that case
*/
window->shaken_loose = !meta_prefs_get_edge_tiling ();
window->tile_mode = META_TILE_NONE;
/* move the unmaximized window to the cursor */
@@ -7839,12 +7919,13 @@ update_move (MetaWindow *window,
* loose or it is still maximized (then move straight)
*/
else if ((window->shaken_loose || META_WINDOW_MAXIMIZED (window)) &&
window->tile_mode == META_TILE_NONE)
window->tile_mode != META_TILE_LEFT && window->tile_mode != META_TILE_RIGHT)
{
const MetaMonitorInfo *wmonitor;
MetaRectangle work_area;
int monitor;
window->tile_mode = META_TILE_NONE;
wmonitor = meta_screen_get_monitor_for_window (window->screen, window);
for (monitor = 0; monitor < window->screen->n_monitor_infos; monitor++)
@@ -7903,7 +7984,7 @@ update_move (MetaWindow *window,
meta_window_get_client_root_coords (window, &old);
/* Don't allow movement in the maximized directions or while tiled */
if (window->maximized_horizontally || META_WINDOW_TILED (window))
if (window->maximized_horizontally || META_WINDOW_TILED_SIDE_BY_SIDE (window))
new_x = old.x;
if (window->maximized_vertically)
new_y = old.y;
@@ -8339,6 +8420,23 @@ check_use_this_motion_notify (MetaWindow *window,
}
}
static void
update_tile_mode (MetaWindow *window)
{
switch (window->tile_mode)
{
case META_TILE_LEFT:
case META_TILE_RIGHT:
if (!META_WINDOW_TILED_SIDE_BY_SIDE (window))
window->tile_mode = META_TILE_NONE;
break;
case META_TILE_MAXIMIZED:
if (!META_WINDOW_MAXIMIZED (window))
window->tile_mode = META_TILE_NONE;
break;
}
}
void
meta_window_handle_mouse_grab_op_event (MetaWindow *window,
XEvent *event)
@@ -8431,9 +8529,7 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
* would break the ability to snap back to the tiled
* state, so we wait until mouse release.
*/
if (!window->maximized_vertically &&
window->tile_mode != META_TILE_NONE)
window->tile_mode = META_TILE_NONE;
update_tile_mode (window);
}
}
@@ -9275,9 +9371,22 @@ transient_has_focus (MetaWindow *window,
return FALSE;
}
/**
* meta_window_appears_focused:
* @window: a #MetaWindow
*
* Determines if the window should be drawn with a focused appearance. This is
* true for focused windows but also true for windows with a focused modal
* dialog attached.
*
* Return value: %TRUE if the window should be drawn with a focused frame
*/
gboolean
meta_window_appears_focused (MetaWindow *window)
{
/* FIXME: meta_window_foreach_transient() iterates over all windows; we
* should eat the complexity to cache a bit for this.
*/
if (!window->has_focus && meta_prefs_get_attach_modal_dialogs ())
{
gboolean focus = FALSE;
@@ -9655,3 +9764,74 @@ meta_window_get_mutter_hints (MetaWindow *window)
return window->mutter_hints;
}
/**
* meta_window_get_frame_type:
* @window: a #MetaWindow
*
* Gets the type of window decorations that should be used for this window.
*
* Return value: the frame type
*/
MetaFrameType
meta_window_get_frame_type (MetaWindow *window)
{
MetaFrameType base_type = META_FRAME_TYPE_LAST;
switch (window->type)
{
case META_WINDOW_NORMAL:
base_type = META_FRAME_TYPE_NORMAL;
break;
case META_WINDOW_DIALOG:
base_type = META_FRAME_TYPE_DIALOG;
break;
case META_WINDOW_MODAL_DIALOG:
if (meta_prefs_get_attach_modal_dialogs () &&
meta_window_get_transient_for (window) != NULL)
base_type = META_FRAME_TYPE_ATTACHED;
else
base_type = META_FRAME_TYPE_MODAL_DIALOG;
break;
case META_WINDOW_MENU:
base_type = META_FRAME_TYPE_MENU;
break;
case META_WINDOW_UTILITY:
base_type = META_FRAME_TYPE_UTILITY;
break;
case META_WINDOW_DESKTOP:
case META_WINDOW_DOCK:
case META_WINDOW_TOOLBAR:
case META_WINDOW_SPLASHSCREEN:
case META_WINDOW_DROPDOWN_MENU:
case META_WINDOW_POPUP_MENU:
case META_WINDOW_TOOLTIP:
case META_WINDOW_NOTIFICATION:
case META_WINDOW_COMBO:
case META_WINDOW_DND:
case META_WINDOW_OVERRIDE_OTHER:
/* No frame */
base_type = META_FRAME_TYPE_LAST;
break;
}
if (base_type == META_FRAME_TYPE_LAST)
{
/* can't add border if undecorated */
return META_FRAME_TYPE_LAST;
}
else if (window->border_only && base_type != META_FRAME_TYPE_ATTACHED)
{
/* override base frame type */
return META_FRAME_TYPE_BORDER;
}
else
{
return base_type;
}
}

View File

@@ -24,6 +24,7 @@
*/
#include <config.h>
#include "screen-private.h"
#include "workspace.h"
#include "workspace-private.h"
#include "boxes-private.h"
@@ -45,7 +46,6 @@ enum {
};
void meta_workspace_queue_calc_showing (MetaWorkspace *workspace);
static void set_active_space_hint (MetaScreen *screen);
static void focus_ancestor_or_mru_window (MetaWorkspace *workspace,
MetaWindow *not_this_one,
guint32 timestamp);
@@ -557,7 +557,7 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
workspace->screen->active_workspace = workspace;
set_active_space_hint (workspace->screen);
meta_screen_set_active_workspace_hint (workspace->screen);
/* If the "show desktop" mode is active for either the old workspace
* or the new one *but not both*, then update the
@@ -618,10 +618,20 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
meta_screen_calc_workspace_layout (workspace->screen, num_workspaces,
new_space, &layout2);
if (layout1.current_col < layout2.current_col)
direction = META_MOTION_RIGHT;
if (layout1.current_col > layout2.current_col)
direction = META_MOTION_LEFT;
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
{
if (layout1.current_col > layout2.current_col)
direction = META_MOTION_RIGHT;
else if (layout1.current_col < layout2.current_col)
direction = META_MOTION_LEFT;
}
else
{
if (layout1.current_col < layout2.current_col)
direction = META_MOTION_RIGHT;
else if (layout1.current_col > layout2.current_col)
direction = META_MOTION_LEFT;
}
if (layout1.current_row < layout2.current_row)
{
@@ -742,32 +752,6 @@ meta_workspace_list_windows (MetaWorkspace *workspace)
return workspace_windows;
}
static void
set_active_space_hint (MetaScreen *screen)
{
unsigned long data[1];
/* this is because we destroy the spaces in order,
* so we always end up setting a current desktop of
* 0 when closing a screen, so lose the current desktop
* on restart. By doing this we keep the current
* desktop on restart.
*/
if (screen->closing > 0)
return;
data[0] = meta_workspace_index (screen->active_workspace);
meta_verbose ("Setting _NET_CURRENT_DESKTOP to %lu\n", data[0]);
meta_error_trap_push (screen->display);
XChangeProperty (screen->display->xdisplay, screen->xroot,
screen->display->atom__NET_CURRENT_DESKTOP,
XA_CARDINAL,
32, PropModeReplace, (guchar*) data, 1);
meta_error_trap_pop (screen->display);
}
void
meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
{

View File

@@ -167,7 +167,7 @@ keybind (switch_panels_backward, handle_switch, META_TAB_LIST_DOCKS,
"using a popup window"))
keybind (cycle_group, handle_cycle, META_TAB_LIST_GROUP,
BINDING_REVERSES, "<Alt>grave",
BINDING_REVERSES, "<Alt>Above_Tab",
_("Move between windows of an application immediately"))
keybind (cycle_group_backward, handle_cycle, META_TAB_LIST_GROUP,
REVERSES_AND_REVERSED, NULL,

View File

@@ -47,7 +47,9 @@ typedef enum
META_FRAME_ALLOWS_MOVE = 1 << 11,
META_FRAME_FULLSCREEN = 1 << 12,
META_FRAME_IS_FLASHING = 1 << 13,
META_FRAME_ABOVE = 1 << 14
META_FRAME_ABOVE = 1 << 14,
META_FRAME_TILED_LEFT = 1 << 15,
META_FRAME_TILED_RIGHT = 1 << 16
} MetaFrameFlags;
typedef enum
@@ -195,6 +197,7 @@ typedef enum
META_FRAME_TYPE_UTILITY,
META_FRAME_TYPE_MENU,
META_FRAME_TYPE_BORDER,
META_FRAME_TYPE_ATTACHED,
META_FRAME_TYPE_LAST
} MetaFrameType;

View File

@@ -39,4 +39,6 @@ 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_background_actor_for_screen (MetaScreen *screen);
#endif

View File

@@ -249,6 +249,9 @@ meta_plugin_get_overlay_group (MetaPlugin *plugin);
ClutterActor *
meta_plugin_get_window_group (MetaPlugin *plugin);
ClutterActor *
meta_plugin_get_background_actor (MetaPlugin *plugin);
ClutterActor *
meta_plugin_get_stage (MetaPlugin *plugin);

View File

@@ -0,0 +1,84 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* MetaShadowFactory:
*
* Create and cache shadow textures for arbitrary window shapes
*
* Copyright (C) 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
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef __META_SHADOW_FACTORY_H__
#define __META_SHADOW_FACTORY_H__
#include <glib-object.h>
/**
* MetaShadowParams:
* The #MetaShadowParams structure holds information about how to draw
* a particular style of shadow.
* @radius: the radius (gaussian standard deviation) of the shadow
* @top_fade: if >= 0, the shadow doesn't extend above the top
* of the shape, and fades out over the given number of pixels
* @x_offset: horizontal offset of the shadow with respect to the
* shape being shadowed, in pixels
* @y_offset: vertical offset of the shadow with respect to the
* shape being shadowed, in pixels
* @opacity: opacity of the shadow, from 0 to 255
*/
typedef struct _MetaShadowParams MetaShadowParams;
struct _MetaShadowParams
{
int radius;
int top_fade;
int x_offset;
int y_offset;
guint8 opacity;
};
#define META_TYPE_SHADOW_FACTORY (meta_shadow_factory_get_type ())
#define META_SHADOW_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SHADOW_FACTORY, MetaShadowFactory))
#define META_SHADOW_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SHADOW_FACTORY, MetaShadowFactoryClass))
#define META_IS_SHADOW_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SHADOW_FACTORY))
#define META_IS_SHADOW_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SHADOW_FACTORY))
#define META_SHADOW_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SHADOW_FACTORY, MetaShadowFactoryClass))
/**
* MetaShadowFactory:
* #MetaShadowFactory is used to create window shadows. It caches shadows internally
* so that multiple shadows created for the same shape with the same radius will
* share the same MetaShadow.
*/
typedef struct _MetaShadowFactory MetaShadowFactory;
typedef struct _MetaShadowFactoryClass MetaShadowFactoryClass;
MetaShadowFactory *meta_shadow_factory_get_default (void);
GType meta_shadow_factory_get_type (void);
void meta_shadow_factory_set_params (MetaShadowFactory *factory,
const char *class_name,
gboolean focused,
MetaShadowParams *params);
void meta_shadow_factory_get_params (MetaShadowFactory *factory,
const char *class_name,
gboolean focused,
MetaShadowParams *params);
#endif /* __META_SHADOW_FACTORY_H__ */

View File

@@ -65,5 +65,6 @@ ClutterActor * meta_window_actor_get_texture (MetaWindowActor *self
gboolean meta_window_actor_is_override_redirect (MetaWindowActor *self);
const char * meta_window_actor_get_description (MetaWindowActor *self);
gboolean meta_window_actor_showing_on_its_workspace (MetaWindowActor *self);
gboolean meta_window_actor_is_destroyed (MetaWindowActor *self);
#endif /* META_WINDOW_ACTOR_H */

View File

@@ -58,9 +58,8 @@ typedef enum
META_PREF_GNOME_ANIMATIONS,
META_PREF_CURSOR_THEME,
META_PREF_CURSOR_SIZE,
META_PREF_COMPOSITING_MANAGER,
META_PREF_RESIZE_WITH_RIGHT_BUTTON,
META_PREF_SIDE_BY_SIDE_TILING,
META_PREF_EDGE_TILING,
META_PREF_FORCE_FULLSCREEN,
META_PREF_CLUTTER_PLUGINS,
META_PREF_LIVE_HIDDEN_WINDOWS,
@@ -99,7 +98,7 @@ gboolean meta_prefs_get_auto_raise (void);
int meta_prefs_get_auto_raise_delay (void);
gboolean meta_prefs_get_gnome_accessibility (void);
gboolean meta_prefs_get_gnome_animations (void);
gboolean meta_prefs_get_side_by_side_tiling (void);
gboolean meta_prefs_get_edge_tiling (void);
const char* meta_prefs_get_command (int i);

View File

@@ -80,4 +80,17 @@ void meta_screen_get_monitor_geometry (MetaScreen *screen,
int monitor,
MetaRectangle *geometry);
typedef enum
{
META_SCREEN_TOPLEFT,
META_SCREEN_TOPRIGHT,
META_SCREEN_BOTTOMLEFT,
META_SCREEN_BOTTOMRIGHT
} MetaScreenCorner;
void meta_screen_override_workspace_layout (MetaScreen *screen,
MetaScreenCorner starting_corner,
gboolean vertical_layout,
int n_rows,
int n_columns);
#endif

View File

@@ -157,6 +157,12 @@ void meta_ui_set_current_theme (const char *name,
gboolean force_reload);
gboolean meta_ui_have_a_theme (void);
/* Not a real key symbol but means "key above the tab key"; this is
* used as the default keybinding for cycle_group.
* 0x2xxxxxxx is a range not used by GDK or X. the remaining digits are
* randomly chosen */
#define META_KEY_ABOVE_TAB 0x2f7259c9
gboolean meta_ui_parse_accelerator (const char *accel,
unsigned int *keysym,
unsigned int *keycode,

View File

@@ -28,6 +28,8 @@
#include <glib.h>
#include <glib-object.h>
#include "common.h"
gboolean meta_is_verbose (void);
void meta_set_verbose (gboolean setting);
gboolean meta_is_debugging (void);
@@ -91,6 +93,7 @@ guint meta_unsigned_long_hash (gconstpointer v);
void meta_print_backtrace (void);
const char* meta_frame_type_to_string (MetaFrameType type);
const char* meta_gravity_to_string (int gravity);
#include <libintl.h>

View File

@@ -69,6 +69,7 @@ GType meta_window_get_type (void);
MetaFrame *meta_window_get_frame (MetaWindow *window);
gboolean meta_window_has_focus (MetaWindow *window);
gboolean meta_window_appears_focused (MetaWindow *window);
gboolean meta_window_is_shaded (MetaWindow *window);
gboolean meta_window_is_override_redirect (MetaWindow *window);
gboolean meta_window_is_skip_taskbar (MetaWindow *window);
@@ -119,6 +120,9 @@ void meta_window_foreach_ancestor (MetaWindow *window,
MetaWindowForeachFunc func,
void *user_data);
MetaMaximizeFlags meta_window_get_maximized (MetaWindow *window);
gboolean meta_window_is_fullscreen (MetaWindow *window);
gboolean meta_window_is_mapped (MetaWindow *window);
gboolean meta_window_toplevel_is_mapped (MetaWindow *window);
gboolean meta_window_get_icon_geometry (MetaWindow *window,
@@ -143,4 +147,7 @@ const char *meta_window_get_client_machine (MetaWindow *window);
gboolean meta_window_is_remote (MetaWindow *window);
gboolean meta_window_is_modal (MetaWindow *window);
const char *meta_window_get_mutter_hints (MetaWindow *window);
MetaFrameType meta_window_get_frame_type (MetaWindow *window);
#endif

View File

@@ -51,7 +51,7 @@ set_gdk_window_struts (GdkWindow *window,
vals[11] = 800;
XChangeProperty (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XWINDOW (window),
GDK_WINDOW_XID (window),
XInternAtom (GDK_WINDOW_XDISPLAY (window),
"_NET_WM_STRUT_PARTIAL", False),
XA_CARDINAL, 32, PropModeReplace,
@@ -125,7 +125,7 @@ set_gdk_window_type (GdkWindow *window,
type, False);
XChangeProperty (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XWINDOW (window),
GDK_WINDOW_XID (window),
XInternAtom (GDK_WINDOW_XDISPLAY (window), "_NET_WM_WINDOW_TYPE", False),
XA_ATOM, 32, PropModeReplace,
(guchar *)atoms,

View File

@@ -55,13 +55,11 @@ draw_handler (GtkWidget *tooltips,
cairo_t *cr,
gpointer user_data)
{
gtk_paint_flat_box (gtk_widget_get_style (tip),
cr,
GTK_STATE_NORMAL, GTK_SHADOW_OUT,
tip, "tooltip",
0, 0,
gtk_widget_get_allocated_width (tip),
gtk_widget_get_allocated_height (tip));
gtk_render_background (gtk_widget_get_style_context (tooltips),
cr,
0, 0,
gtk_widget_get_allocated_width (tooltips),
gtk_widget_get_allocated_height (tooltips));
return FALSE;
}

View File

@@ -43,12 +43,11 @@
#define DEFAULT_INNER_BUTTON_BORDER 3
static void meta_frames_destroy (GtkWidget *object);
static void meta_frames_finalize (GObject *object);
static void meta_frames_style_set (GtkWidget *widget,
GtkStyle *prev_style);
static void meta_frames_map (GtkWidget *widget);
static void meta_frames_unmap (GtkWidget *widget);
static void meta_frames_destroy (GtkWidget *object);
static void meta_frames_finalize (GObject *object);
static void meta_frames_style_updated (GtkWidget *widget);
static void meta_frames_map (GtkWidget *widget);
static void meta_frames_unmap (GtkWidget *widget);
static void meta_frames_update_prelit_control (MetaFrames *frames,
MetaUIFrame *frame,
@@ -137,7 +136,7 @@ meta_frames_class_init (MetaFramesClass *class)
widget_class->destroy = meta_frames_destroy;
widget_class->style_set = meta_frames_style_set;
widget_class->style_updated = meta_frames_style_updated;
widget_class->map = meta_frames_map;
widget_class->unmap = meta_frames_unmap;
@@ -422,8 +421,7 @@ reattach_style_func (gpointer key, gpointer value, gpointer data)
}
static void
meta_frames_style_set (GtkWidget *widget,
GtkStyle *prev_style)
meta_frames_style_updated (GtkWidget *widget)
{
MetaFrames *frames;
@@ -434,7 +432,7 @@ meta_frames_style_set (GtkWidget *widget,
g_hash_table_foreach (frames->frames,
reattach_style_func, frames);
GTK_WIDGET_CLASS (meta_frames_parent_class)->style_set (widget, prev_style);
GTK_WIDGET_CLASS (meta_frames_parent_class)->style_updated (widget);
}
static void
@@ -577,12 +575,9 @@ meta_frames_attach_style (MetaFrames *frames,
MetaUIFrame *frame)
{
if (frame->style != NULL)
gtk_style_detach (frame->style);
g_object_unref (frame->style);
/* Weirdly, gtk_style_attach() steals a reference count from the style passed in */
g_object_ref (gtk_widget_get_style (GTK_WIDGET (frames)));
frame->style = gtk_style_attach (gtk_widget_get_style (GTK_WIDGET (frames)),
frame->window);
frame->style = g_object_ref (gtk_widget_get_style_context (GTK_WIDGET (frames)));
}
void
@@ -653,7 +648,7 @@ meta_frames_unmanage_window (MetaFrames *frames,
g_hash_table_remove (frames->frames, &frame->xwindow);
gtk_style_detach (frame->style);
g_object_unref (frame->style);
gdk_window_destroy (frame->window);
@@ -2398,20 +2393,6 @@ meta_frames_paint (MetaFrames *frames,
default:
break;
}
/* Map button function states to button position states */
button_states[META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND] =
button_states[META_BUTTON_TYPE_MENU];
button_states[META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND] =
META_BUTTON_STATE_NORMAL;
button_states[META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND] =
META_BUTTON_STATE_NORMAL;
button_states[META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND] =
button_states[META_BUTTON_TYPE_MINIMIZE];
button_states[META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND] =
button_states[META_BUTTON_TYPE_MAXIMIZE];
button_states[META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND] =
button_states[META_BUTTON_TYPE_CLOSE];
meta_core_get (display, frame->xwindow,
META_CORE_GET_FRAME_FLAGS, &flags,
@@ -2483,8 +2464,7 @@ meta_frames_set_window_background (MetaFrames *frames,
}
else
{
gtk_style_set_background (frame->style,
frame->window, GTK_STATE_NORMAL);
gtk_style_context_set_background (frame->style, frame->window);
}
}

View File

@@ -75,7 +75,7 @@ struct _MetaUIFrame
{
Window xwindow;
GdkWindow *window;
GtkStyle *style;
GtkStyleContext *style;
MetaFrameStyle *cache_style;
PangoLayout *layout;
int text_height;

View File

@@ -401,10 +401,10 @@ meta_window_menu_new (MetaFrames *frames,
n_workspaces, active_workspace);
window = gtk_widget_get_window (GTK_WIDGET (frames));
display = gdk_x11_drawable_get_xdisplay (window);
display = GDK_WINDOW_XDISPLAY (window);
screen = gdk_window_get_screen (window);
xroot = GDK_DRAWABLE_XID (gdk_screen_get_root_window (screen));
xroot = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
submenu = gtk_menu_new ();

View File

@@ -255,6 +255,7 @@ meta_accel_label_draw (GtkWidget *widget,
if (allocation.width >= requisition.width + ac_width)
{
GtkStyleContext *style;
PangoLayout *label_layout;
PangoLayout *accel_layout;
GtkLabel *label = GTK_LABEL (widget);
@@ -302,14 +303,15 @@ meta_accel_label_draw (GtkWidget *widget,
y = (allocation.height - (requisition.height - ypad * 2)) * yalign + 1.5;
gtk_paint_layout (gtk_widget_get_style (widget),
cr,
gtk_widget_get_state (widget),
FALSE,
widget,
"accellabel",
x, y,
accel_layout);
style = gtk_widget_get_style_context (widget);
gtk_style_context_save (style);
gtk_style_context_set_state (style,
gtk_widget_get_state_flags (widget));
gtk_render_layout (gtk_widget_get_style_context (widget),
cr,
x, y,
accel_layout);
gtk_style_context_restore (style);
g_object_unref (accel_layout);
}

View File

@@ -78,7 +78,6 @@ outline_window_draw (GtkWidget *widget,
{
MetaTabPopup *popup;
TabEntry *te;
GtkStyle *style;
popup = data;
@@ -86,10 +85,9 @@ outline_window_draw (GtkWidget *widget,
return FALSE;
te = popup->current_selected_entry;
style = gtk_widget_get_style (widget);
cairo_set_line_width (cr, 1.0);
gdk_cairo_set_source_color (cr, &style->white);
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
cairo_rectangle (cr,
0.5, 0.5,
@@ -479,6 +477,7 @@ display_entry (MetaTabPopup *popup,
{
cairo_region_t *region;
cairo_region_t *inner_region;
GdkRGBA black = { 0.0, 0.0, 0.0, 1.0 };
window = gtk_widget_get_window (popup->outline_window);
@@ -495,9 +494,7 @@ display_entry (MetaTabPopup *popup,
te->rect.x, te->rect.y,
te->rect.width, te->rect.height);
gdk_window_set_background (window,
&gtk_widget_get_style (popup->outline_window)->black);
gdk_window_set_background_rgba (window, &black);
region = cairo_region_create_rectangle (&rect);
@@ -709,9 +706,8 @@ meta_select_image_draw (GtkWidget *widget,
{
GtkMisc *misc;
GtkRequisition requisition;
GtkStyle *style;
GtkStateType state;
GdkWindow *window;
GtkStyleContext *context;
GdkRGBA color;
int x, y, w, h;
gint xpad, ypad;
gfloat xalign, yalign;
@@ -731,12 +727,15 @@ meta_select_image_draw (GtkWidget *widget,
w = requisition.width - OUTSIDE_SELECT_RECT * 2 - 1;
h = requisition.height - OUTSIDE_SELECT_RECT * 2 - 1;
window = gtk_widget_get_window (widget);
style = gtk_widget_get_style (widget);
state = gtk_widget_get_state (widget);
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_state (context,
gtk_widget_get_state_flags (widget));
gtk_style_context_lookup_color (context, "color", &color);
cairo_set_line_width (cr, 2.0);
gdk_cairo_set_source_color (cr, &style->fg[state]);
cairo_set_source_rgb (cr, color.red, color.green, color.blue);
cairo_rectangle (cr, x, y, w + 1, h + 1);
cairo_stroke (cr);
@@ -891,7 +890,6 @@ meta_select_workspace_draw (GtkWidget *widget,
MetaWorkspace *workspace;
WnckWindowDisplayInfo *windows;
GtkAllocation allocation;
GtkStyle *style;
int i, n_windows;
GList *tmp, *list;
@@ -949,11 +947,18 @@ meta_select_workspace_draw (GtkWidget *widget,
if (META_SELECT_WORKSPACE (widget)->selected)
{
style = gtk_widget_get_style (widget);
GtkStyleContext *context;
GdkRGBA color;
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_state (context,
gtk_widget_get_state_flags (widget));
gtk_style_context_lookup_color (context, "color", &color);
gdk_cairo_set_source_color (cr,
&style->fg[gtk_widget_get_state (widget)]);
cairo_set_line_width (cr, SELECT_OUTLINE_WIDTH);
cairo_set_source_rgb (cr, color.red, color.green, color.blue);
cairo_rectangle (cr,
SELECT_OUTLINE_WIDTH / 2.0, SELECT_OUTLINE_WIDTH / 2.0,

View File

@@ -23,19 +23,17 @@
#include "gradient.h"
#include <gtk/gtk.h>
typedef void (* RenderGradientFunc) (GdkDrawable *drawable,
cairo_t *cr,
typedef void (* RenderGradientFunc) (cairo_t *cr,
int width,
int height);
static void
draw_checkerboard (GdkDrawable *drawable,
int width,
int height)
draw_checkerboard (cairo_t *cr,
int width,
int height)
{
gint i, j, xcount, ycount;
GdkColor color1, color2;
cairo_t *cr;
#define CHECK_SIZE 10
#define SPACING 2
@@ -48,8 +46,6 @@ draw_checkerboard (GdkDrawable *drawable,
color2.green = 50000;
color2.blue = 50000;
cr = gdk_cairo_create (drawable);
xcount = 0;
i = SPACING;
while (i < width)
@@ -77,13 +73,10 @@ draw_checkerboard (GdkDrawable *drawable,
i += CHECK_SIZE + SPACING;
++xcount;
}
cairo_destroy (cr);
}
static void
render_simple (GdkDrawable *drawable,
cairo_t *cr,
render_simple (cairo_t *cr,
int width, int height,
MetaGradientType type,
gboolean with_alpha)
@@ -115,7 +108,7 @@ render_simple (GdkDrawable *drawable,
alphas, G_N_ELEMENTS (alphas),
META_GRADIENT_HORIZONTAL);
draw_checkerboard (drawable, width, height);
draw_checkerboard (cr , width, height);
}
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
@@ -126,40 +119,35 @@ render_simple (GdkDrawable *drawable,
}
static void
render_vertical_func (GdkDrawable *drawable,
cairo_t *cr,
render_vertical_func (cairo_t *cr,
int width, int height)
{
render_simple (drawable, cr, width, height, META_GRADIENT_VERTICAL, FALSE);
render_simple (cr, width, height, META_GRADIENT_VERTICAL, FALSE);
}
static void
render_horizontal_func (GdkDrawable *drawable,
cairo_t *cr,
render_horizontal_func (cairo_t *cr,
int width, int height)
{
render_simple (drawable, cr, width, height, META_GRADIENT_HORIZONTAL, FALSE);
render_simple (cr, width, height, META_GRADIENT_HORIZONTAL, FALSE);
}
static void
render_diagonal_func (GdkDrawable *drawable,
cairo_t *cr,
render_diagonal_func (cairo_t *cr,
int width, int height)
{
render_simple (drawable, cr, width, height, META_GRADIENT_DIAGONAL, FALSE);
render_simple (cr, width, height, META_GRADIENT_DIAGONAL, FALSE);
}
static void
render_diagonal_alpha_func (GdkDrawable *drawable,
cairo_t *cr,
render_diagonal_alpha_func (cairo_t *cr,
int width, int height)
{
render_simple (drawable, cr, width, height, META_GRADIENT_DIAGONAL, TRUE);
render_simple (cr, width, height, META_GRADIENT_DIAGONAL, TRUE);
}
static void
render_multi (GdkDrawable *drawable,
cairo_t *cr,
render_multi (cairo_t *cr,
int width, int height,
MetaGradientType type)
{
@@ -186,32 +174,28 @@ render_multi (GdkDrawable *drawable,
}
static void
render_vertical_multi_func (GdkDrawable *drawable,
cairo_t *cr,
render_vertical_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (drawable, cr, width, height, META_GRADIENT_VERTICAL);
render_multi (cr, width, height, META_GRADIENT_VERTICAL);
}
static void
render_horizontal_multi_func (GdkDrawable *drawable,
cairo_t *cr,
render_horizontal_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (drawable, cr, width, height, META_GRADIENT_HORIZONTAL);
render_multi (cr, width, height, META_GRADIENT_HORIZONTAL);
}
static void
render_diagonal_multi_func (GdkDrawable *drawable,
cairo_t *cr,
render_diagonal_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (drawable, cr, width, height, META_GRADIENT_DIAGONAL);
render_multi (cr, width, height, META_GRADIENT_DIAGONAL);
}
static void
render_interwoven_func (GdkDrawable *drawable,
cairo_t *cr,
render_interwoven_func (cairo_t *cr,
int width, int height)
{
GdkPixbuf *pixbuf;
@@ -235,31 +219,28 @@ render_interwoven_func (GdkDrawable *drawable,
}
static gboolean
expose_callback (GtkWidget *widget,
GdkEventExpose *event,
gpointer data)
draw_callback (GtkWidget *widget,
cairo_t *cr,
gpointer data)
{
RenderGradientFunc func = data;
GdkWindow *window;
GtkAllocation allocation;
GtkStyle *style;
cairo_t *cr;
GtkStyleContext *style;
GdkRGBA color;
style = gtk_widget_get_style (widget);
gtk_widget_get_allocation (widget, &allocation);
style = gtk_widget_get_style_context (widget);
window = gtk_widget_get_window (widget);
cr = gdk_cairo_create (window);
gdk_cairo_set_source_color (cr, &style->fg[gtk_widget_get_state (widget)]);
gtk_style_context_save (style);
gtk_style_context_set_state (style, gtk_widget_get_state_flags (widget));
gtk_style_context_lookup_color (style, "foreground-color", &color);
gtk_style_context_restore (style);
(* func) (gtk_widget_get_window (widget),
cr,
allocation.width,
allocation.height);
cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha);
cairo_destroy (cr);
(* func) (cr,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
return TRUE;
return FALSE;
}
static GtkWidget*
@@ -280,8 +261,8 @@ create_gradient_window (const char *title,
gtk_window_set_default_size (GTK_WINDOW (window), 175, 175);
g_signal_connect (G_OBJECT (drawing_area),
"expose_event",
G_CALLBACK (expose_callback),
"draw",
G_CALLBACK (draw_callback),
func);
gtk_container_add (GTK_CONTAINER (window), drawing_area);
@@ -294,31 +275,29 @@ create_gradient_window (const char *title,
static void
meta_gradient_test (void)
{
GtkWidget *window;
create_gradient_window ("Simple vertical",
render_vertical_func);
window = create_gradient_window ("Simple vertical",
render_vertical_func);
window = create_gradient_window ("Simple horizontal",
render_horizontal_func);
create_gradient_window ("Simple horizontal",
render_horizontal_func);
window = create_gradient_window ("Simple diagonal",
render_diagonal_func);
create_gradient_window ("Simple diagonal",
render_diagonal_func);
window = create_gradient_window ("Multi vertical",
render_vertical_multi_func);
window = create_gradient_window ("Multi horizontal",
render_horizontal_multi_func);
create_gradient_window ("Multi vertical",
render_vertical_multi_func);
window = create_gradient_window ("Multi diagonal",
render_diagonal_multi_func);
create_gradient_window ("Multi horizontal",
render_horizontal_multi_func);
window = create_gradient_window ("Interwoven",
render_interwoven_func);
create_gradient_window ("Multi diagonal",
render_diagonal_multi_func);
window = create_gradient_window ("Simple diagonal with horizontal multi alpha",
render_diagonal_alpha_func);
create_gradient_window ("Interwoven",
render_interwoven_func);
create_gradient_window ("Simple diagonal with horizontal multi alpha",
render_diagonal_alpha_func);
}

View File

@@ -38,7 +38,7 @@
* look out for.
*/
#define THEME_MAJOR_VERSION 3
#define THEME_MINOR_VERSION 1
#define THEME_MINOR_VERSION 3
#define THEME_VERSION (1000 * THEME_MAJOR_VERSION + THEME_MINOR_VERSION)
#define METACITY_THEME_FILENAME_FORMAT "metacity-theme-%d.xml"
@@ -1257,7 +1257,8 @@ parse_toplevel_element (GMarkupParseContext *context,
type = meta_frame_type_from_string (type_name);
if (type == META_FRAME_TYPE_LAST)
if (type == META_FRAME_TYPE_LAST ||
(type == META_FRAME_TYPE_ATTACHED && peek_required_version (info) < 3002))
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Unknown type \"%s\" on <%s> element"),
@@ -2954,6 +2955,7 @@ parse_style_element (GMarkupParseContext *context,
const char *function = NULL;
const char *state = NULL;
const char *draw_ops = NULL;
gint required_version;
if (!locate_attributes (context, element_name, attribute_names, attribute_values,
error,
@@ -2972,13 +2974,14 @@ parse_style_element (GMarkupParseContext *context,
return;
}
required_version = peek_required_version (info);
if (meta_theme_earliest_version_with_button (info->button_type) >
info->theme->format_version)
(guint)required_version)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Button function \"%s\" does not exist in this version (%d, need %d)"),
function,
info->theme->format_version,
required_version,
meta_theme_earliest_version_with_button (info->button_type)
);
return;
@@ -3187,6 +3190,31 @@ parse_style_set_element (GMarkupParseContext *context,
meta_frame_style_ref (frame_style);
info->style_set->maximized_styles[frame_focus] = frame_style;
break;
case META_FRAME_STATE_TILED_LEFT:
if (info->style_set->tiled_left_styles[frame_focus])
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Style has already been specified for state %s focus %s"),
state, focus);
return;
}
meta_frame_style_ref (frame_style);
info->style_set->tiled_left_styles[frame_focus] = frame_style;
break;
case META_FRAME_STATE_TILED_RIGHT:
if (info->style_set->tiled_right_styles[frame_focus])
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Style has already been specified for state %s focus %s"),
state, focus);
return;
}
meta_frame_style_ref (frame_style);
info->style_set->tiled_right_styles[frame_focus] = frame_style;
break;
meta_frame_style_ref (frame_style);
info->style_set->tiled_right_styles[frame_focus] = frame_style;
break;
case META_FRAME_STATE_SHADED:
if (info->style_set->shaded_styles[frame_resize][frame_focus])
{
@@ -3209,6 +3237,28 @@ parse_style_set_element (GMarkupParseContext *context,
meta_frame_style_ref (frame_style);
info->style_set->maximized_and_shaded_styles[frame_focus] = frame_style;
break;
case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
if (info->style_set->tiled_left_and_shaded_styles[frame_focus])
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Style has already been specified for state %s focus %s"),
state, focus);
return;
}
meta_frame_style_ref (frame_style);
info->style_set->tiled_left_and_shaded_styles[frame_focus] = frame_style;
break;
case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
if (info->style_set->tiled_right_and_shaded_styles[frame_focus])
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Style has already been specified for state %s focus %s"),
state, focus);
return;
}
meta_frame_style_ref (frame_style);
info->style_set->tiled_right_and_shaded_styles[frame_focus] = frame_style;
break;
case META_FRAME_STATE_LAST:
g_assert_not_reached ();
break;
@@ -3827,7 +3877,7 @@ end_element_handler (GMarkupParseContext *context,
g_assert (info->style);
if (!meta_frame_style_validate (info->style,
info->theme->format_version,
peek_required_version (info),
error))
{
add_context_to_error (error, context);

View File

@@ -234,7 +234,7 @@ struct _MetaFrameGeometry
/* used for a memset hack */
#define ADDRESS_OF_BUTTON_RECTS(fgeom) (((char*)(fgeom)) + G_STRUCT_OFFSET (MetaFrameGeometry, close_rect))
#define LENGTH_OF_BUTTON_RECTS (G_STRUCT_OFFSET (MetaFrameGeometry, right_right_background) + sizeof (GdkRectangle) - G_STRUCT_OFFSET (MetaFrameGeometry, close_rect))
#define LENGTH_OF_BUTTON_RECTS (G_STRUCT_OFFSET (MetaFrameGeometry, right_single_background) + sizeof (GdkRectangle) - G_STRUCT_OFFSET (MetaFrameGeometry, close_rect))
/* The button rects (if changed adjust memset hack) */
MetaButtonSpace close_rect;
@@ -252,10 +252,17 @@ struct _MetaFrameGeometry
GdkRectangle left_left_background;
GdkRectangle left_middle_backgrounds[MAX_MIDDLE_BACKGROUNDS];
GdkRectangle left_right_background;
GdkRectangle left_single_background;
GdkRectangle right_left_background;
GdkRectangle right_middle_backgrounds[MAX_MIDDLE_BACKGROUNDS];
GdkRectangle right_right_background;
GdkRectangle right_single_background;
/* End of button rects (if changed adjust memset hack) */
/* Saved button layout */
MetaButtonLayout button_layout;
int n_left_buttons;
int n_right_buttons;
/* Round corners */
guint top_left_corner_rounded_radius;
@@ -642,9 +649,11 @@ typedef enum
META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND,
META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND,
META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND,
META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND,
META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND,
META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND,
META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND,
META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND,
META_BUTTON_TYPE_CLOSE,
META_BUTTON_TYPE_MAXIMIZE,
META_BUTTON_TYPE_MINIMIZE,
@@ -767,8 +776,12 @@ typedef enum
{
META_FRAME_STATE_NORMAL,
META_FRAME_STATE_MAXIMIZED,
META_FRAME_STATE_TILED_LEFT,
META_FRAME_STATE_TILED_RIGHT,
META_FRAME_STATE_SHADED,
META_FRAME_STATE_MAXIMIZED_AND_SHADED,
META_FRAME_STATE_TILED_LEFT_AND_SHADED,
META_FRAME_STATE_TILED_RIGHT_AND_SHADED,
META_FRAME_STATE_LAST
} MetaFrameState;
@@ -805,8 +818,12 @@ struct _MetaFrameStyleSet
MetaFrameStyleSet *parent;
MetaFrameStyle *normal_styles[META_FRAME_RESIZE_LAST][META_FRAME_FOCUS_LAST];
MetaFrameStyle *maximized_styles[META_FRAME_FOCUS_LAST];
MetaFrameStyle *tiled_left_styles[META_FRAME_FOCUS_LAST];
MetaFrameStyle *tiled_right_styles[META_FRAME_FOCUS_LAST];
MetaFrameStyle *shaded_styles[META_FRAME_RESIZE_LAST][META_FRAME_FOCUS_LAST];
MetaFrameStyle *maximized_and_shaded_styles[META_FRAME_FOCUS_LAST];
MetaFrameStyle *tiled_left_and_shaded_styles[META_FRAME_FOCUS_LAST];
MetaFrameStyle *tiled_right_and_shaded_styles[META_FRAME_FOCUS_LAST];
};
/**
@@ -958,7 +975,7 @@ void meta_draw_op_draw (const MetaDrawOp *op,
MetaRectangle logical_region);
void meta_draw_op_draw_with_style (const MetaDrawOp *op,
GtkStyle *style_gtk,
GtkStyleContext *style_gtk,
GtkWidget *widget,
cairo_t *cr,
const MetaDrawInfo *info,
@@ -974,7 +991,7 @@ void meta_draw_op_list_draw (const MetaDrawOpList *op_list,
const MetaDrawInfo *info,
MetaRectangle rect);
void meta_draw_op_list_draw_with_style (const MetaDrawOpList *op_list,
GtkStyle *style_gtk,
GtkStyleContext *style_gtk,
GtkWidget *widget,
cairo_t *cr,
const MetaDrawInfo *info,
@@ -1018,7 +1035,7 @@ void meta_frame_style_draw (MetaFrameStyle *style,
void meta_frame_style_draw_with_style (MetaFrameStyle *style,
GtkStyle *style_gtk,
GtkStyleContext *style_gtk,
GtkWidget *widget,
cairo_t *cr,
const MetaFrameGeometry *fgeom,
@@ -1084,7 +1101,7 @@ void meta_theme_draw_frame_by_name (MetaTheme *theme,
GdkPixbuf *icon);
void meta_theme_draw_frame_with_style (MetaTheme *theme,
GtkStyle *style_gtk,
GtkStyleContext *style_gtk,
GtkWidget *widget,
cairo_t *cr,
MetaFrameType type,
@@ -1189,7 +1206,6 @@ const char* meta_frame_resize_to_string (MetaFrameResize r
MetaFrameFocus meta_frame_focus_from_string (const char *str);
const char* meta_frame_focus_to_string (MetaFrameFocus focus);
MetaFrameType meta_frame_type_from_string (const char *str);
const char* meta_frame_type_to_string (MetaFrameType type);
MetaGradientType meta_gradient_type_from_string (const char *str);
const char* meta_gradient_type_to_string (MetaGradientType type);
GtkStateType meta_gtk_state_from_string (const char *str);

View File

@@ -234,7 +234,7 @@ dialog_contents (void)
vbox = gtk_vbox_new (FALSE, 0);
action_area = gtk_hbutton_box_new ();
action_area = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_button_box_set_layout (GTK_BUTTON_BOX (action_area),
GTK_BUTTONBOX_END);
@@ -407,6 +407,10 @@ get_window_contents (MetaFrameType type,
case META_FRAME_TYPE_BORDER:
*title = _("Border");
return border_only_contents ();
case META_FRAME_TYPE_ATTACHED:
*title = _("Attached Modal Dialog");
return dialog_contents ();
case META_FRAME_TYPE_LAST:
g_assert_not_reached ();
@@ -454,6 +458,9 @@ get_window_flags (MetaFrameType type)
case META_FRAME_TYPE_BORDER:
break;
case META_FRAME_TYPE_ATTACHED:
break;
case META_FRAME_TYPE_LAST:
g_assert_not_reached ();
@@ -465,7 +472,7 @@ get_window_flags (MetaFrameType type)
static GtkWidget*
preview_collection (int font_size,
PangoFontDescription *base_desc)
const PangoFontDescription *base_desc)
{
GtkWidget *box;
GtkWidget *sw;
@@ -773,7 +780,8 @@ benchmark_summary (void)
int
main (int argc, char **argv)
{
GtkStyle *style;
GtkStyleContext *style;
const PangoFontDescription *font_desc;
GtkWidget *window;
GtkWidget *collection;
GError *err;
@@ -850,28 +858,29 @@ main (int argc, char **argv)
G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_realize (window);
style = gtk_widget_get_style (window);
style = gtk_widget_get_style_context (window);
font_desc = gtk_style_context_get_font (style, 0);
g_assert (style);
g_assert (style->font_desc);
g_assert (font_desc);
notebook = gtk_notebook_new ();
gtk_container_add (GTK_CONTAINER (window), notebook);
collection = preview_collection (FONT_SIZE_NORMAL,
style->font_desc);
font_desc);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
collection,
gtk_label_new (_("Normal Title Font")));
collection = preview_collection (FONT_SIZE_SMALL,
style->font_desc);
font_desc);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
collection,
gtk_label_new (_("Small Title Font")));
collection = preview_collection (FONT_SIZE_LARGE,
style->font_desc);
font_desc);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
collection,
gtk_label_new (_("Large Title Font")));
@@ -922,7 +931,12 @@ get_flags (GtkWidget *widget)
static int
get_text_height (GtkWidget *widget)
{
return meta_pango_font_desc_get_text_height (gtk_widget_get_style (widget)->font_desc,
GtkStyleContext *style;
const PangoFontDescription *font_desc;
style = gtk_widget_get_style_context (widget);
font_desc = gtk_style_context_get_font (style, 0);
return meta_pango_font_desc_get_text_height (font_desc,
gtk_widget_get_pango_context (widget));
}

View File

@@ -452,6 +452,38 @@ meta_frame_layout_get_borders (const MetaFrameLayout *layout,
}
}
static MetaButtonType
map_button_function_to_type (MetaButtonFunction function)
{
switch (function)
{
case META_BUTTON_FUNCTION_SHADE:
return META_BUTTON_TYPE_SHADE;
case META_BUTTON_FUNCTION_ABOVE:
return META_BUTTON_TYPE_ABOVE;
case META_BUTTON_FUNCTION_STICK:
return META_BUTTON_TYPE_STICK;
case META_BUTTON_FUNCTION_UNSHADE:
return META_BUTTON_TYPE_UNSHADE;
case META_BUTTON_FUNCTION_UNABOVE:
return META_BUTTON_TYPE_UNABOVE;
case META_BUTTON_FUNCTION_UNSTICK:
return META_BUTTON_TYPE_UNSTICK;
case META_BUTTON_FUNCTION_MENU:
return META_BUTTON_TYPE_MENU;
case META_BUTTON_FUNCTION_MINIMIZE:
return META_BUTTON_TYPE_MINIMIZE;
case META_BUTTON_FUNCTION_MAXIMIZE:
return META_BUTTON_TYPE_MAXIMIZE;
case META_BUTTON_FUNCTION_CLOSE:
return META_BUTTON_TYPE_CLOSE;
case META_BUTTON_FUNCTION_LAST:
return META_BUTTON_TYPE_LAST;
}
return META_BUTTON_TYPE_LAST;
}
static MetaButtonSpace*
rect_for_function (MetaFrameGeometry *fgeom,
MetaFrameFlags flags,
@@ -702,7 +734,9 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
for (i = 0; i < n_left; i++)
{
if (i == 0) /* prefer left background if only one button */
if (n_left == 1)
left_bg_rects[i] = &fgeom->left_single_background;
else if (i == 0)
left_bg_rects[i] = &fgeom->left_left_background;
else if (i == (n_left - 1))
left_bg_rects[i] = &fgeom->left_right_background;
@@ -712,8 +746,9 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
for (i = 0; i < n_right; i++)
{
/* prefer right background if only one button */
if (i == (n_right - 1))
if (n_right == 1)
right_bg_rects[i] = &fgeom->right_single_background;
else if (i == (n_right - 1))
right_bg_rects[i] = &fgeom->right_right_background;
else if (i == 0)
right_bg_rects[i] = &fgeom->right_left_background;
@@ -808,6 +843,11 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
n_left, n_right);
}
}
/* Save the button layout */
fgeom->button_layout = *button_layout;
fgeom->n_left_buttons = n_left;
fgeom->n_right_buttons = n_right;
/* center buttons vertically */
button_y = (fgeom->top_height -
@@ -833,7 +873,9 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
rect->visible.width = button_width;
rect->visible.height = button_height;
if (flags & META_FRAME_MAXIMIZED)
if (flags & META_FRAME_MAXIMIZED ||
flags & META_FRAME_TILED_LEFT ||
flags & META_FRAME_TILED_RIGHT)
{
rect->clickable.x = rect->visible.x;
rect->clickable.y = 0;
@@ -3430,6 +3472,30 @@ fill_env (MetaPositionExprEnv *env,
env->theme = meta_current_theme;
}
static GtkStateFlags
state_flags_from_gtk_state (GtkStateType state)
{
switch (state)
{
case GTK_STATE_NORMAL:
return 0;
case GTK_STATE_PRELIGHT:
return GTK_STATE_FLAG_PRELIGHT;
case GTK_STATE_ACTIVE:
return GTK_STATE_FLAG_ACTIVE;
case GTK_STATE_SELECTED:
return GTK_STATE_FLAG_SELECTED;
case GTK_STATE_INSENSITIVE:
return GTK_STATE_FLAG_INSENSITIVE;
case GTK_STATE_INCONSISTENT:
return GTK_STATE_FLAG_INCONSISTENT;
case GTK_STATE_FOCUSED:
return GTK_STATE_FLAG_FOCUSED;
}
return 0;
}
/* This code was originally rendering anti-aliased using X primitives, and
* now has been switched to draw anti-aliased using cairo. In general, the
* closest correspondence between X rendering and cairo rendering is given
@@ -3443,7 +3509,7 @@ fill_env (MetaPositionExprEnv *env,
*/
static void
meta_draw_op_draw_with_env (const MetaDrawOp *op,
GtkStyle *style_gtk,
GtkStyleContext *style_gtk,
GtkWidget *widget,
cairo_t *cr,
const MetaDrawInfo *info,
@@ -3453,6 +3519,7 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
GdkColor color;
cairo_save (cr);
gtk_style_context_save (style_gtk);
cairo_set_line_width (cr, 1.0);
@@ -3702,21 +3769,36 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
case META_DRAW_GTK_ARROW:
{
int rx, ry, rwidth, rheight;
double angle = 0, size;
rx = parse_x_position_unchecked (op->data.gtk_arrow.x, env);
ry = parse_y_position_unchecked (op->data.gtk_arrow.y, env);
rwidth = parse_size_unchecked (op->data.gtk_arrow.width, env);
rheight = parse_size_unchecked (op->data.gtk_arrow.height, env);
gtk_paint_arrow (style_gtk,
cr,
op->data.gtk_arrow.state,
op->data.gtk_arrow.shadow,
widget,
"metacity",
op->data.gtk_arrow.arrow,
op->data.gtk_arrow.filled,
rx, ry, rwidth, rheight);
size = MAX(rwidth, rheight);
switch (op->data.gtk_arrow.arrow)
{
case GTK_ARROW_UP:
angle = 0;
break;
case GTK_ARROW_RIGHT:
angle = M_PI / 2;
break;
case GTK_ARROW_DOWN:
angle = M_PI;
break;
case GTK_ARROW_LEFT:
angle = 3 * M_PI / 2;
break;
case GTK_ARROW_NONE:
return;
}
gtk_style_context_set_state (style_gtk,
state_flags_from_gtk_state (op->data.gtk_arrow.state));
gtk_render_arrow (style_gtk, cr, angle, rx, ry, size);
}
break;
@@ -3729,13 +3811,10 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
rwidth = parse_size_unchecked (op->data.gtk_box.width, env);
rheight = parse_size_unchecked (op->data.gtk_box.height, env);
gtk_paint_box (style_gtk,
cr,
op->data.gtk_box.state,
op->data.gtk_box.shadow,
widget,
"metacity",
rx, ry, rwidth, rheight);
gtk_style_context_set_state (style_gtk,
state_flags_from_gtk_state (op->data.gtk_box.state));
gtk_render_background (style_gtk, cr, rx, ry, rwidth, rheight);
gtk_render_frame (style_gtk, cr, rx, ry, rwidth, rheight);
}
break;
@@ -3747,12 +3826,9 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
ry1 = parse_y_position_unchecked (op->data.gtk_vline.y1, env);
ry2 = parse_y_position_unchecked (op->data.gtk_vline.y2, env);
gtk_paint_vline (style_gtk,
cr,
op->data.gtk_vline.state,
widget,
"metacity",
ry1, ry2, rx);
gtk_style_context_set_state (style_gtk,
state_flags_from_gtk_state (op->data.gtk_vline.state));
gtk_render_line (style_gtk, cr, rx, ry1, rx, ry2);
}
break;
@@ -3897,15 +3973,16 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op,
}
cairo_restore (cr);
gtk_style_context_restore (style_gtk);
}
void
meta_draw_op_draw_with_style (const MetaDrawOp *op,
GtkStyle *style_gtk,
GtkWidget *widget,
cairo_t *cr,
const MetaDrawInfo *info,
MetaRectangle logical_region)
GtkStyleContext *style_gtk,
GtkWidget *widget,
cairo_t *cr,
const MetaDrawInfo *info,
MetaRectangle logical_region)
{
MetaPositionExprEnv env;
@@ -3924,8 +4001,8 @@ meta_draw_op_draw (const MetaDrawOp *op,
const MetaDrawInfo *info,
MetaRectangle logical_region)
{
meta_draw_op_draw_with_style (op, gtk_widget_get_style (widget), widget,
cr, info, logical_region);
meta_draw_op_draw_with_style (op, gtk_widget_get_style_context (widget),
widget, cr, info, logical_region);
}
/**
@@ -3981,11 +4058,11 @@ meta_draw_op_list_unref (MetaDrawOpList *op_list)
void
meta_draw_op_list_draw_with_style (const MetaDrawOpList *op_list,
GtkStyle *style_gtk,
GtkWidget *widget,
cairo_t *cr,
const MetaDrawInfo *info,
MetaRectangle rect)
GtkStyleContext *style_gtk,
GtkWidget *widget,
cairo_t *cr,
const MetaDrawInfo *info,
MetaRectangle rect)
{
int i;
MetaPositionExprEnv env;
@@ -4046,7 +4123,7 @@ meta_draw_op_list_draw (const MetaDrawOpList *op_list,
MetaRectangle rect)
{
meta_draw_op_list_draw_with_style (op_list, gtk_widget_get_style (widget), widget,
meta_draw_op_list_draw_with_style (op_list, gtk_widget_get_style_context (widget), widget,
cr, info, rect);
}
@@ -4198,6 +4275,66 @@ meta_frame_style_unref (MetaFrameStyle *style)
}
}
static MetaButtonState
map_button_state (MetaButtonType button_type,
const MetaFrameGeometry *fgeom,
int middle_bg_offset,
MetaButtonState button_states[META_BUTTON_TYPE_LAST])
{
MetaButtonFunction function = META_BUTTON_FUNCTION_LAST;
switch (button_type)
{
/* First hande functions, which map directly */
case META_BUTTON_TYPE_SHADE:
case META_BUTTON_TYPE_ABOVE:
case META_BUTTON_TYPE_STICK:
case META_BUTTON_TYPE_UNSHADE:
case META_BUTTON_TYPE_UNABOVE:
case META_BUTTON_TYPE_UNSTICK:
case META_BUTTON_TYPE_MENU:
case META_BUTTON_TYPE_MINIMIZE:
case META_BUTTON_TYPE_MAXIMIZE:
case META_BUTTON_TYPE_CLOSE:
return button_states[button_type];
/* Map position buttons to the corresponding function */
case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
if (fgeom->n_right_buttons > 0)
function = fgeom->button_layout.right_buttons[0];
break;
case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
if (fgeom->n_right_buttons > 0)
function = fgeom->button_layout.right_buttons[fgeom->n_right_buttons - 1];
break;
case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
if (middle_bg_offset + 1 < fgeom->n_right_buttons)
function = fgeom->button_layout.right_buttons[middle_bg_offset + 1];
break;
case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
if (fgeom->n_left_buttons > 0)
function = fgeom->button_layout.left_buttons[0];
break;
case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
if (fgeom->n_left_buttons > 0)
function = fgeom->button_layout.left_buttons[fgeom->n_left_buttons - 1];
break;
case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
if (middle_bg_offset + 1 < fgeom->n_left_buttons)
function = fgeom->button_layout.left_buttons[middle_bg_offset + 1];
break;
case META_BUTTON_TYPE_LAST:
break;
}
if (function != META_BUTTON_FUNCTION_LAST)
return button_states[map_button_function_to_type (function)];
return META_BUTTON_STATE_LAST;
}
static MetaDrawOpList*
get_button (MetaFrameStyle *style,
MetaButtonType type,
@@ -4214,10 +4351,19 @@ get_button (MetaFrameStyle *style,
parent = parent->parent;
}
/* We fall back to middle button backgrounds if we don't
* have the ones on the sides
/* We fall back to the side buttons if we don't have
* single button backgrounds, and to middle button
* backgrounds if we don't have the ones on the sides
*/
if (op_list == NULL &&
type == META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND)
return get_button (style, META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND, state);
if (op_list == NULL &&
type == META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND)
return get_button (style, META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND, state);
if (op_list == NULL &&
(type == META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND ||
type == META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND))
@@ -4292,6 +4438,10 @@ button_rect (MetaButtonType type,
case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
*rect = fgeom->left_right_background;
break;
case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
*rect = fgeom->left_single_background;
break;
case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
*rect = fgeom->right_left_background;
@@ -4304,6 +4454,10 @@ button_rect (MetaButtonType type,
case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
*rect = fgeom->right_right_background;
break;
case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
*rect = fgeom->right_single_background;
break;
case META_BUTTON_TYPE_CLOSE:
*rect = fgeom->close_rect.visible;
@@ -4353,17 +4507,17 @@ button_rect (MetaButtonType type,
void
meta_frame_style_draw_with_style (MetaFrameStyle *style,
GtkStyle *style_gtk,
GtkWidget *widget,
cairo_t *cr,
const MetaFrameGeometry *fgeom,
int client_width,
int client_height,
PangoLayout *title_layout,
int text_height,
MetaButtonState button_states[META_BUTTON_TYPE_LAST],
GdkPixbuf *mini_icon,
GdkPixbuf *icon)
GtkStyleContext *style_gtk,
GtkWidget *widget,
cairo_t *cr,
const MetaFrameGeometry *fgeom,
int client_width,
int client_height,
PangoLayout *title_layout,
int text_height,
MetaButtonState button_states[META_BUTTON_TYPE_LAST],
GdkPixbuf *mini_icon,
GdkPixbuf *icon)
{
int i, j;
GdkRectangle titlebar_rect;
@@ -4521,10 +4675,10 @@ meta_frame_style_draw_with_style (MetaFrameStyle *style,
m_rect = meta_rect (rect.x, rect.y, rect.width, rect.height);
meta_draw_op_list_draw_with_style (op_list,
style_gtk,
widget,
cr,
&draw_info,
m_rect);
widget,
cr,
&draw_info,
m_rect);
}
}
@@ -4540,9 +4694,13 @@ meta_frame_style_draw_with_style (MetaFrameStyle *style,
j = 0;
while (j < META_BUTTON_TYPE_LAST)
{
MetaButtonState button_state;
button_rect (j, fgeom, middle_bg_offset, &rect);
op_list = get_button (style, j, button_states[j]);
button_state = map_button_state (j, fgeom, middle_bg_offset, button_states);
op_list = get_button (style, j, button_state);
if (op_list)
{
@@ -4600,7 +4758,7 @@ meta_frame_style_draw (MetaFrameStyle *style,
GdkPixbuf *mini_icon,
GdkPixbuf *icon)
{
meta_frame_style_draw_with_style (style, gtk_widget_get_style (widget), widget,
meta_frame_style_draw_with_style (style, gtk_widget_get_style_context (widget), widget,
cr, fgeom, client_width, client_height,
title_layout, text_height,
button_states, mini_icon, icon);
@@ -4659,7 +4817,11 @@ meta_frame_style_set_unref (MetaFrameStyleSet *style_set)
}
free_focus_styles (style_set->maximized_styles);
free_focus_styles (style_set->tiled_left_styles);
free_focus_styles (style_set->tiled_right_styles);
free_focus_styles (style_set->maximized_and_shaded_styles);
free_focus_styles (style_set->tiled_left_and_shaded_styles);
free_focus_styles (style_set->tiled_right_and_shaded_styles);
if (style_set->parent)
meta_frame_style_set_unref (style_set->parent);
@@ -4711,9 +4873,21 @@ get_style (MetaFrameStyleSet *style_set,
case META_FRAME_STATE_MAXIMIZED:
styles = style_set->maximized_styles;
break;
case META_FRAME_STATE_TILED_LEFT:
styles = style_set->tiled_left_styles;
break;
case META_FRAME_STATE_TILED_RIGHT:
styles = style_set->tiled_right_styles;
break;
case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
styles = style_set->maximized_and_shaded_styles;
break;
case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
styles = style_set->tiled_left_and_shaded_styles;
break;
case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
styles = style_set->tiled_right_and_shaded_styles;
break;
case META_FRAME_STATE_NORMAL:
case META_FRAME_STATE_SHADED:
case META_FRAME_STATE_LAST:
@@ -4723,6 +4897,19 @@ get_style (MetaFrameStyleSet *style_set,
style = styles[focus];
/* Tiled states are optional, try falling back to non-tiled states */
if (style == NULL)
{
if (state == META_FRAME_STATE_TILED_LEFT ||
state == META_FRAME_STATE_TILED_RIGHT)
style = get_style (style_set, META_FRAME_STATE_NORMAL,
resize, focus);
else if (state == META_FRAME_STATE_TILED_LEFT_AND_SHADED ||
state == META_FRAME_STATE_TILED_RIGHT_AND_SHADED)
style = get_style (style_set, META_FRAME_STATE_SHADED,
resize, focus);
}
/* Try parent if we failed here */
if (style == NULL && style_set->parent)
style = get_style (style_set->parent, state, resize, focus);
@@ -4992,7 +5179,7 @@ meta_theme_validate (MetaTheme *theme,
}
for (i = 0; i < (int)META_FRAME_TYPE_LAST; i++)
if (theme->style_sets_by_type[i] == NULL)
if (i != (int)META_FRAME_TYPE_ATTACHED && theme->style_sets_by_type[i] == NULL)
{
g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
_("No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element"),
@@ -5074,7 +5261,10 @@ theme_get_style (MetaTheme *theme,
style_set = theme->style_sets_by_type[type];
/* Right now the parser forces a style set for all types,
if (style_set == NULL && type == META_FRAME_TYPE_ATTACHED)
style_set = theme->style_sets_by_type[META_FRAME_TYPE_BORDER];
/* Right now the parser forces a style set for all other types,
* but this fallback code is here in case I take that out.
*/
if (style_set == NULL)
@@ -5082,7 +5272,8 @@ theme_get_style (MetaTheme *theme,
if (style_set == NULL)
return NULL;
switch (flags & (META_FRAME_MAXIMIZED | META_FRAME_SHADED))
switch (flags & (META_FRAME_MAXIMIZED | META_FRAME_SHADED |
META_FRAME_TILED_LEFT | META_FRAME_TILED_RIGHT))
{
case 0:
state = META_FRAME_STATE_NORMAL;
@@ -5090,12 +5281,24 @@ theme_get_style (MetaTheme *theme,
case META_FRAME_MAXIMIZED:
state = META_FRAME_STATE_MAXIMIZED;
break;
case META_FRAME_TILED_LEFT:
state = META_FRAME_STATE_TILED_LEFT;
break;
case META_FRAME_TILED_RIGHT:
state = META_FRAME_STATE_TILED_RIGHT;
break;
case META_FRAME_SHADED:
state = META_FRAME_STATE_SHADED;
break;
case (META_FRAME_MAXIMIZED | META_FRAME_SHADED):
state = META_FRAME_STATE_MAXIMIZED_AND_SHADED;
break;
case (META_FRAME_TILED_LEFT | META_FRAME_SHADED):
state = META_FRAME_STATE_TILED_LEFT_AND_SHADED;
break;
case (META_FRAME_TILED_RIGHT | META_FRAME_SHADED):
state = META_FRAME_STATE_TILED_RIGHT_AND_SHADED;
break;
default:
g_assert_not_reached ();
state = META_FRAME_STATE_LAST; /* compiler */
@@ -5168,19 +5371,19 @@ meta_theme_get_title_scale (MetaTheme *theme,
void
meta_theme_draw_frame_with_style (MetaTheme *theme,
GtkStyle *style_gtk,
GtkWidget *widget,
cairo_t *cr,
MetaFrameType type,
MetaFrameFlags flags,
int client_width,
int client_height,
PangoLayout *title_layout,
int text_height,
const MetaButtonLayout *button_layout,
MetaButtonState button_states[META_BUTTON_TYPE_LAST],
GdkPixbuf *mini_icon,
GdkPixbuf *icon)
GtkStyleContext *style_gtk,
GtkWidget *widget,
cairo_t *cr,
MetaFrameType type,
MetaFrameFlags flags,
int client_width,
int client_height,
PangoLayout *title_layout,
int text_height,
const MetaButtonLayout *button_layout,
MetaButtonState button_states[META_BUTTON_TYPE_LAST],
GdkPixbuf *mini_icon,
GdkPixbuf *icon)
{
MetaFrameGeometry fgeom;
MetaFrameStyle *style;
@@ -5228,7 +5431,7 @@ meta_theme_draw_frame (MetaTheme *theme,
GdkPixbuf *mini_icon,
GdkPixbuf *icon)
{
meta_theme_draw_frame_with_style (theme, gtk_widget_get_style (widget), widget,
meta_theme_draw_frame_with_style (theme, gtk_widget_get_style_context (widget), widget,
cr, type,flags,
client_width, client_height,
title_layout, text_height,
@@ -5615,11 +5818,13 @@ meta_gtk_widget_get_font_desc (GtkWidget *widget,
double scale,
const PangoFontDescription *override)
{
GtkStyleContext *style;
PangoFontDescription *font_desc;
g_return_val_if_fail (gtk_widget_get_realized (widget), NULL);
font_desc = pango_font_description_copy (gtk_widget_get_style (widget)->font_desc);
style = gtk_widget_get_style_context (widget);
font_desc = pango_font_description_copy (gtk_style_context_get_font (style, 0));
if (override)
pango_font_description_merge (font_desc, override, TRUE);
@@ -5771,12 +5976,16 @@ meta_button_type_from_string (const char *str, MetaTheme *theme)
return META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND;
else if (strcmp ("left_right_background", str) == 0)
return META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND;
else if (strcmp ("left_single_background", str) == 0)
return META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND;
else if (strcmp ("right_left_background", str) == 0)
return META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND;
else if (strcmp ("right_middle_background", str) == 0)
return META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND;
else if (strcmp ("right_right_background", str) == 0)
return META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND;
else if (strcmp ("right_single_background", str) == 0)
return META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND;
else
return META_BUTTON_TYPE_LAST;
}
@@ -5812,12 +6021,16 @@ meta_button_type_to_string (MetaButtonType type)
return "left_middle_background";
case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
return "left_right_background";
case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
return "left_single_background";
case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
return "right_left_background";
case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
return "right_middle_background";
case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
return "right_right_background";
case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
return "right_single_background";
case META_BUTTON_TYPE_LAST:
break;
}
@@ -5899,10 +6112,18 @@ meta_frame_state_from_string (const char *str)
return META_FRAME_STATE_NORMAL;
else if (strcmp ("maximized", str) == 0)
return META_FRAME_STATE_MAXIMIZED;
else if (strcmp ("tiled_left", str) == 0)
return META_FRAME_STATE_TILED_LEFT;
else if (strcmp ("tiled_right", str) == 0)
return META_FRAME_STATE_TILED_RIGHT;
else if (strcmp ("shaded", str) == 0)
return META_FRAME_STATE_SHADED;
else if (strcmp ("maximized_and_shaded", str) == 0)
return META_FRAME_STATE_MAXIMIZED_AND_SHADED;
else if (strcmp ("tiled_left_and_shaded", str) == 0)
return META_FRAME_STATE_TILED_LEFT_AND_SHADED;
else if (strcmp ("tiled_right_and_shaded", str) == 0)
return META_FRAME_STATE_TILED_RIGHT_AND_SHADED;
else
return META_FRAME_STATE_LAST;
}
@@ -5916,10 +6137,18 @@ meta_frame_state_to_string (MetaFrameState state)
return "normal";
case META_FRAME_STATE_MAXIMIZED:
return "maximized";
case META_FRAME_STATE_TILED_LEFT:
return "tiled_left";
case META_FRAME_STATE_TILED_RIGHT:
return "tiled_right";
case META_FRAME_STATE_SHADED:
return "shaded";
case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
return "maximized_and_shaded";
case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
return "tiled_left_and_shaded";
case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
return "tiled_right_and_shaded";
case META_FRAME_STATE_LAST:
break;
}
@@ -6004,6 +6233,8 @@ meta_frame_type_from_string (const char *str)
return META_FRAME_TYPE_MENU;
else if (strcmp ("border", str) == 0)
return META_FRAME_TYPE_BORDER;
else if (strcmp ("attached", str) == 0)
return META_FRAME_TYPE_ATTACHED;
#if 0
else if (strcmp ("toolbar", str) == 0)
return META_FRAME_TYPE_TOOLBAR;
@@ -6012,6 +6243,14 @@ meta_frame_type_from_string (const char *str)
return META_FRAME_TYPE_LAST;
}
/**
* meta_frame_type_to_string:
*
* Converts a frame type enum value to the name string that would
* appear in the theme definition file.
*
* Return value: the string value
*/
const char*
meta_frame_type_to_string (MetaFrameType type)
{
@@ -6029,6 +6268,8 @@ meta_frame_type_to_string (MetaFrameType type)
return "menu";
case META_FRAME_TYPE_BORDER:
return "border";
case META_FRAME_TYPE_ATTACHED:
return "attached";
#if 0
case META_FRAME_TYPE_TOOLBAR:
return "toolbar";
@@ -6074,16 +6315,20 @@ meta_gradient_type_to_string (MetaGradientType type)
GtkStateType
meta_gtk_state_from_string (const char *str)
{
if (strcmp ("normal", str) == 0 || strcmp ("NORMAL", str) == 0)
if (g_ascii_strcasecmp ("normal", str) == 0)
return GTK_STATE_NORMAL;
else if (strcmp ("prelight", str) == 0 || strcmp ("PRELIGHT", str) == 0)
else if (g_ascii_strcasecmp ("prelight", str) == 0)
return GTK_STATE_PRELIGHT;
else if (strcmp ("active", str) == 0 || strcmp ("ACTIVE", str) == 0)
else if (g_ascii_strcasecmp ("active", str) == 0)
return GTK_STATE_ACTIVE;
else if (strcmp ("selected", str) == 0 || strcmp ("SELECTED", str) == 0)
else if (g_ascii_strcasecmp ("selected", str) == 0)
return GTK_STATE_SELECTED;
else if (strcmp ("insensitive", str) == 0 || strcmp ("INSENSITIVE", str) == 0)
else if (g_ascii_strcasecmp ("insensitive", str) == 0)
return GTK_STATE_INSENSITIVE;
else if (g_ascii_strcasecmp ("inconsistent", str) == 0)
return GTK_STATE_INCONSISTENT;
else if (g_ascii_strcasecmp ("focused", str) == 0)
return GTK_STATE_FOCUSED;
else
return -1; /* hack */
}
@@ -6103,6 +6348,10 @@ meta_gtk_state_to_string (GtkStateType state)
return "SELECTED";
case GTK_STATE_INSENSITIVE:
return "INSENSITIVE";
case GTK_STATE_INCONSISTENT:
return "INCONSISTENT";
case GTK_STATE_FOCUSED:
return "FOCUSED";
}
return "<unknown>";
@@ -6671,6 +6920,10 @@ meta_theme_earliest_version_with_button (MetaButtonType type)
case META_BUTTON_TYPE_UNSTICK:
return 2000;
case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
return 3003;
default:
meta_warning("Unknown button %d\n", type);
return 1000;

View File

@@ -36,8 +36,7 @@ struct _MetaTilePreview {
GtkWidget *preview_window;
gulong create_serial;
GdkColor *preview_color;
guchar preview_alpha;
GdkRGBA *preview_color;
MetaRectangle tile_rect;
@@ -57,22 +56,23 @@ meta_tile_preview_draw (GtkWidget *widget,
{
/* Fill the preview area with a transparent color */
cairo_set_source_rgba (cr,
(double)preview->preview_color->red / 0xFFFF,
(double)preview->preview_color->green / 0xFFFF,
(double)preview->preview_color->blue / 0xFFFF,
(double)preview->preview_alpha / 0xFF);
preview->preview_color->red,
preview->preview_color->green,
preview->preview_color->blue,
preview->preview_color->alpha);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
/* Use the opaque color for the border */
gdk_cairo_set_source_color (cr, preview->preview_color);
cairo_set_source_rgb (cr,
preview->preview_color->red,
preview->preview_color->green,
preview->preview_color->blue);
}
else
{
GtkStyle *style = gtk_widget_get_style (preview->preview_window);
gdk_cairo_set_source_color (cr, &style->white);
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
cairo_rectangle (cr,
OUTLINE_WIDTH - 0.5, OUTLINE_WIDTH - 0.5,
@@ -90,37 +90,6 @@ meta_tile_preview_draw (GtkWidget *widget,
return FALSE;
}
static void
on_preview_window_style_set (GtkWidget *widget,
GtkStyle *previous,
gpointer user_data)
{
MetaTilePreview *preview = user_data;
GtkStyle *style;
style = gtk_rc_get_style_by_paths (gtk_widget_get_settings (widget),
"GtkWindow.GtkIconView",
"GtkWindow.GtkIconView",
GTK_TYPE_ICON_VIEW);
if (style != NULL)
g_object_ref (style);
else
style = gtk_style_new ();
gtk_style_get (style, GTK_TYPE_ICON_VIEW,
"selection-box-color", &preview->preview_color,
"selection-box-alpha", &preview->preview_alpha,
NULL);
if (!preview->preview_color)
{
GdkColor selection = style->base[GTK_STATE_SELECTED];
preview->preview_color = gdk_color_copy (&selection);
}
g_object_unref (style);
}
MetaTilePreview *
meta_tile_preview_new (int screen_number,
gboolean composited)
@@ -138,7 +107,6 @@ meta_tile_preview_new (int screen_number,
gtk_widget_set_app_paintable (preview->preview_window, TRUE);
preview->preview_color = NULL;
preview->preview_alpha = 0xFF;
preview->tile_rect.x = preview->tile_rect.y = 0;
preview->tile_rect.width = preview->tile_rect.height = 0;
@@ -148,11 +116,38 @@ meta_tile_preview_new (int screen_number,
if (preview->has_alpha)
{
GtkStyleContext *context;
GtkWidgetPath *path;
guchar selection_alpha = 0xFF;
gtk_widget_set_visual (preview->preview_window,
gdk_screen_get_rgba_visual (screen));
g_signal_connect (preview->preview_window, "style-set",
G_CALLBACK (on_preview_window_style_set), preview);
path = gtk_widget_path_new ();
gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW);
context = gtk_style_context_new ();
gtk_style_context_set_path (context, path);
gtk_style_context_add_class (context,
GTK_STYLE_CLASS_RUBBERBAND);
gtk_widget_path_free (path);
gtk_style_context_get (context, GTK_STATE_FLAG_SELECTED,
"background-color", &preview->preview_color,
NULL);
/* The background-color for the .rubberband class should probably
* contain the correct alpha value - unfortunately, at least for now
* it doesn't. Hopefully the following workaround can be removed
* when GtkIconView gets ported to GtkStyleContext.
*/
gtk_style_context_get_style (context,
"selection-box-alpha", &selection_alpha,
NULL);
preview->preview_color->alpha = (double)selection_alpha / 0xFF;
g_object_unref (context);
}
/* We make an assumption that XCreateWindow will be the first operation
@@ -173,7 +168,7 @@ meta_tile_preview_free (MetaTilePreview *preview)
gtk_widget_destroy (preview->preview_window);
if (preview->preview_color)
gdk_color_free (preview->preview_color);
gdk_rgba_free (preview->preview_color);
g_free (preview);
}
@@ -195,7 +190,7 @@ meta_tile_preview_show (MetaTilePreview *preview,
gtk_widget_show (preview->preview_window);
window = gtk_widget_get_window (preview->preview_window);
meta_core_lower_beneath_focus_window (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
GDK_WINDOW_XWINDOW (window),
GDK_WINDOW_XID (window),
gtk_get_current_event_time ());
old_rect.x = old_rect.y = 0;
@@ -214,10 +209,9 @@ meta_tile_preview_show (MetaTilePreview *preview,
{
cairo_region_t *outer_region, *inner_region;
GdkRectangle outer_rect, inner_rect;
GdkColor black;
GdkRGBA black = { 0.0, 0.0, 0.0, 1.0 };
black = gtk_widget_get_style (preview->preview_window)->black;
gdk_window_set_background (window, &black);
gdk_window_set_background_rgba (window, &black);
outer_rect.x = outer_rect.y = 0;
outer_rect.width = preview->tile_rect.width;
@@ -254,5 +248,5 @@ meta_tile_preview_get_xwindow (MetaTilePreview *preview,
if (create_serial)
*create_serial = preview->create_serial;
return GDK_WINDOW_XWINDOW (window);
return GDK_WINDOW_XID (window);
}

View File

@@ -60,6 +60,16 @@ struct _MetaUI
void
meta_ui_init (int *argc, char ***argv)
{
/* As of 2.91.7, Gdk uses XI2 by default, which conflicts with the
* direct X calls we use - in particular, events caused by calls to
* XGrabPointer/XGrabKeyboard are no longer understood by GDK, while
* GDK will no longer generate the core XEvents we process.
* So at least for now, enforce the previous behavior.
*/
#if GTK_CHECK_VERSION(2, 91, 7)
gdk_disable_multidevice ();
#endif
if (!gtk_init_check (argc, argv))
meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL));
@@ -91,6 +101,7 @@ static gboolean
maybe_redirect_mouse_event (XEvent *xevent)
{
GdkDisplay *gdisplay;
GdkDeviceManager *gmanager;
MetaUI *ui;
GdkEvent *gevent;
GdkWindow *gdk_window;
@@ -118,7 +129,7 @@ maybe_redirect_mouse_event (XEvent *xevent)
if (!ui)
return FALSE;
gdk_window = gdk_window_lookup_for_display (gdisplay, window);
gdk_window = gdk_x11_window_lookup_for_display (gdisplay, window);
if (gdk_window == NULL)
return FALSE;
@@ -196,7 +207,8 @@ maybe_redirect_mouse_event (XEvent *xevent)
}
/* If we've gotten here, we've created the gdk_event and should send it on */
gdk_event_set_device (gevent, gdk_display_get_core_pointer (gdisplay));
gmanager = gdk_display_get_device_manager (gdisplay);
gdk_event_set_device (gevent, gdk_device_manager_get_client_pointer (gmanager));
gtk_main_do_event (gevent);
gdk_event_free (gevent);
@@ -399,8 +411,10 @@ meta_ui_map_frame (MetaUI *ui,
Window xwindow)
{
GdkWindow *window;
GdkDisplay *display;
window = gdk_xid_table_lookup (xwindow);
display = gdk_x11_lookup_xdisplay (ui->xdisplay);
window = gdk_x11_window_lookup_for_display (display, xwindow);
if (window)
gdk_window_show_unraised (window);
@@ -411,8 +425,10 @@ meta_ui_unmap_frame (MetaUI *ui,
Window xwindow)
{
GdkWindow *window;
GdkDisplay *display;
window = gdk_xid_table_lookup (xwindow);
display = gdk_x11_lookup_xdisplay (ui->xdisplay);
window = gdk_x11_window_lookup_for_display (display, xwindow);
if (window)
gdk_window_hide (window);
@@ -641,8 +657,10 @@ meta_ui_window_should_not_cause_focus (Display *xdisplay,
Window xwindow)
{
GdkWindow *window;
GdkDisplay *display;
window = gdk_xid_table_lookup (xwindow);
display = gdk_x11_lookup_xdisplay (xdisplay);
window = gdk_x11_window_lookup_for_display (display, xwindow);
/* we shouldn't cause focus if we're an override redirect
* toplevel which is not foreign
@@ -657,17 +675,20 @@ char*
meta_text_property_to_utf8 (Display *xdisplay,
const XTextProperty *prop)
{
GdkDisplay *display;
char **list;
int count;
char *retval;
list = NULL;
count = gdk_text_property_to_utf8_list (gdk_x11_xatom_to_atom (prop->encoding),
prop->format,
prop->value,
prop->nitems,
&list);
display = gdk_x11_lookup_xdisplay (xdisplay);
count = gdk_text_property_to_utf8_list_for_display (display,
gdk_x11_xatom_to_atom_for_display (display, prop->encoding),
prop->format,
prop->value,
prop->nitems,
&list);
if (count == 0)
retval = NULL;
@@ -692,9 +713,9 @@ meta_ui_theme_get_frame_borders (MetaUI *ui,
int *right_width)
{
int text_height;
GtkStyleContext *style = NULL;
PangoContext *context;
const PangoFontDescription *font_desc;
GtkStyle *default_style;
if (meta_ui_have_a_theme ())
{
@@ -703,8 +724,8 @@ meta_ui_theme_get_frame_borders (MetaUI *ui,
if (!font_desc)
{
default_style = gtk_widget_get_default_style ();
font_desc = default_style->font_desc;
style = gtk_style_context_new ();
font_desc = gtk_style_context_get_font (style, 0);
}
text_height = meta_pango_font_desc_get_text_height (font_desc, context);
@@ -718,6 +739,9 @@ meta_ui_theme_get_frame_borders (MetaUI *ui,
{
*top_height = *bottom_height = *left_width = *right_width = 0;
}
if (style != NULL)
g_object_unref (style);
}
void
@@ -740,14 +764,50 @@ meta_ui_accelerator_parse (const char *accel,
guint *keycode,
GdkModifierType *keymask)
{
const char *above_tab;
if (accel[0] == '0' && accel[1] == 'x')
{
*keysym = 0;
*keycode = (guint) strtoul (accel, NULL, 16);
*keymask = 0;
return;
}
else
gtk_accelerator_parse (accel, keysym, keymask);
/* The key name 'Above_Tab' is special - it's not an actual keysym name,
* but rather refers to the key above the tab key. In order to use
* the GDK parsing for modifiers in combination with it, we substitute
* it with 'Tab' temporarily before calling gtk_accelerator_parse().
*/
#define is_word_character(c) (g_ascii_isalnum(c) || ((c) == '_'))
#define ABOVE_TAB "Above_Tab"
#define ABOVE_TAB_LEN 9
above_tab = strstr (accel, ABOVE_TAB);
if (above_tab &&
(above_tab == accel || !is_word_character (above_tab[-1])) &&
!is_word_character (above_tab[ABOVE_TAB_LEN]))
{
char *before = g_strndup (accel, above_tab - accel);
char *after = g_strdup (above_tab + ABOVE_TAB_LEN);
char *replaced = g_strconcat (before, "Tab", after, NULL);
gtk_accelerator_parse (replaced, NULL, keymask);
g_free (before);
g_free (after);
g_free (replaced);
*keysym = META_KEY_ABOVE_TAB;
return;
}
#undef is_word_character
#undef ABOVE_TAB
#undef ABOVE_TAB_LEN
gtk_accelerator_parse (accel, keysym, keymask);
}
gboolean
@@ -892,9 +952,11 @@ gboolean
meta_ui_window_is_widget (MetaUI *ui,
Window xwindow)
{
GdkDisplay *display;
GdkWindow *window;
window = gdk_xid_table_lookup (xwindow);
display = gdk_x11_lookup_xdisplay (ui->xdisplay);
window = gdk_x11_window_lookup_for_display (display, xwindow);
if (window)
{