Compare commits

..

19 Commits

Author SHA1 Message Date
Owen W. Taylor
8a0de6dfd3 Avoid restacking animating hidden actors
Since the stack passed to the compositor now accurately reflects
the X stacking order, we need to treat hidden windows (which are
at the bottom of the X stacking order) specially - when the
compositor stacking order is synced, try to keep animating hidden
actors in their old positions in the stack.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-27 09:58:45 -04:00
Owen W. Taylor
2bf0b2b6de Merge branch 'master' into override-redirect-exclusion 2009-06-19 11:42:03 -04:00
Owen W. Taylor
eed2a2d324 Fix shadowing problem breaking MetaStackTracker
A variable shadowing problem introduced in cleanup was causing
queued elements to be removed too early.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-17 14:23:57 -04:00
Owen W. Taylor
9828007a02 Merge branch 'master' into override-redirect-exclusion
Conflicts:
	src/core/bell.c
2009-06-17 13:40:42 -04:00
Owen W. Taylor
1f890672bb Use MetaStackTracker to avoid a round-trip XQueryTree()
With MetaStackTracker, it's no longer necessary to XQueryTree to
get a reasonably-up-to-date view of the server stacking order.

Add some comments explaining unclear aspects of
raise_window_relative_to_managed_windows() and with future possible
improvements.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-16 09:56:43 -04:00
Owen W. Taylor
ef966854d5 Don't do stacking for override-redirect windows
Don't add override-redirect windows to MetaStack; we shouldn't
be restacking them.

Since we *aren't* stacking the override-redirect windows, we need to
be careful that to ignore them when looking for the top managed
window.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-16 09:56:42 -04:00
Owen W. Taylor
7309b6cfe3 Move compositor-stack handling to MetaStackTracker
In order to properly track the stacking order for override-redirect
windows, move meta_compositor_sync_stack() call into MetaStackTracker.
In the new location, we sync the stack as a before-redraw idle function,
rather then using the freeze-thaw facilities of MetaStack. This is
simpler, and also properly compresses multiple stack changes on
notifications received from the X server.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-16 09:56:42 -04:00
Owen W. Taylor
3705a224f0 Add better tracking of real stacking order
Wedging override-redirect windows into the constraint code in stack.c
results in Mutter getting confused about the stacking order of
these windows with respect to other windows, and may also in some
cases cause Mutter to restack override-redirect windows.

core/stack-tracker.c core/stack-tracker.h: MetaStackTracker - combine
  events received from the X server with local changes we have made
  to come up with the best possible idea of what the stacking order
  is at any one point in time.

core/screen.c core/screen-private.h: Create a MetaStackTracker for
  the screen.

core/display.c: Feed relevant events to MetaStackTracker

core/frame.c core/screen.c core/stack.c: When we make changes to the
  stacking order or add windows, record those changes immediatley
  in MetaStackTracker so we have the information without waiting
  for a round-trip.

include/ui.h ui/ui.c: meta_ui_create_frame_window add a return value
  for the X request serial used to create the window.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-16 09:56:42 -04:00
Owen W. Taylor
2ebedb822d Avoid moving and resizing override-redirect windows
Override-redirect windows should not be moved or resized by the
window manager.

- Mark override-redirect windows as already placed to avoid
  placing them when first shown.
- Don't move-resize newly created override-redirect MetaWindow
- Don't queue a resize on override-redirect windows when reading
  their WM_TRANSIENT_FOR hint.
- Add g_return_if_fail (!window->override_redirect) to catch
  unexpected code paths that might result in override-redirect
  windows being moved or resized.
http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
d6576d9b70 Don't add override-redirect windows to workspaces
Normally a window that is "on all workspaces", is also on a particular
workspace (to deal with being unstuck.) This is pointless for
override-redirect windows.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
6516c19ec5 Ignore client messages sent to override-redirect windows
If someone asks us to close, maximize, etc, an override-redirect
window, just ignore the request.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
5518fee61c meta_screen_foreach_window(): Skip override-redirect windows
Don't include override-redirect windows when iterating the windows
in the screen. We don't need them for any of the current uses:

 - Queueing redraws and resizes on managed windows
 - Checking which windows should be added to a new workspace

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
ace0521cba meta_display_list_windows: Exclude override-redirect
Don't include override-redirect windows in the list return by
meta_display_list_windows(), since we almost never want to handle
them when considering "all window" for the display. Add a separate
meta_display_list_all_windows() that includes override-redirect
windows.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
0091a3aab5 Don't read most properties for override-redirect windows
Skipping handling of properties for override redirect windows has
two advantages: first it reduces the amount of work needed to get
an override-redirect window (menu, tooltip, drag icon) onto the
screen. But more importantly, it reduces the number of code-paths
for an override-redirect to get into some code portion where it
isn't expected.

* Integrate the list of properties we load initially with the
  list of property hooks; this avoids having two separate lists
  that we have to keep in sync.

* Add a flag to MetaWindowPropHooks to indicate whether the
  property should be handled for override-redirect windows;
  currently we load a) properties that identify the window -
  useful for debugging purposes b) WM_TRANSIENT_FOR (could be
  used to associate menus with toplevels.)

* For properties that aren't always loaded through window-props.c,
  add !window->override checks to places that trigger loading,
  and add g_return_if_fail(!window->override) to the load
  functions as a double-check.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
268b92a4ec Add checks against inappropriate changes to override-redirect window
Add g_return_if_fail() to check that window-management functions like
meta_window_maximize() aren't called on override-redirect windows.

This reveals that were were "unminimizing" override-redirect windows
when adding them; avoid doing that.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:41 -04:00
Owen W. Taylor
29bb4c27e3 Fix property notifications for certain properties
If a property has a reload function, but the standard property-fetching
mechanism isn't used (hooks->type == META_PROP_VALUE_INVALID), then the
a logic error (introduced in January) caused the hook to never be run.

This meant that changes to struts and icons weren't noticed.

Same as: http://bugzilla.gnome.org/show_bug.cgi?id=572573
The fix here is different in detail from that applied to Metacity, but
similar in spirit.

http://bugzilla.gnome.org/show_bug.cgi?id=585980
2009-06-16 09:56:41 -04:00
Owen W. Taylor
bd3bdc51b9 Load NET_WM_USER_TIME from the right window
On subsequent changes, if there is a NET_WM_USER_TIME_WINDOW, then
read the property from that rather than from the main window.
(Fix an accidental regression: the right Window was being computed
but no longer passed in.)

http://bugzilla.gnome.org/show_bug.cgi?id=585979
2009-06-16 09:56:41 -04:00
Owen W. Taylor
0123dab87a Fix missing static for meta_window_show()
Definition of meta_window_show() was missing static although it
was forward-declared with static.

http://bugzilla.gnome.org/show_bug.cgi?id=585978
2009-06-16 09:56:41 -04:00
Owen W. Taylor
413acc9574 Regularize main loop priorities
If there is a client that is continually redrawing, then
sources that are less-prioritized than CLUTTER_PRIORITY_REDRAW
will never get run. This patch sorts out how all the different
main loop sources fit in CLUTTER_PRIORITY_REDRAW.

common.h: Document all the relevant priorities and how they
  fit in with each other.
ui.h common.h: Move META_PRIORITY_RESIZE to to common.h with
  other priorities.
src/core/window.c src/core/screen.c: Change calc-showing,
  update-icon, and update-work-area idles to be prioritized above
  redraws so they don't get starved.
bell.c: Make the visual bell priority the same as the clutter
  redraw priority.
delete.c: Use a G_PRIORITY_DEFAULT idle when responding to the
  dialog response; we want to handle it as soon as practical.

http://bugzilla.gnome.org/show_bug.cgi?id=568874
2009-06-16 09:56:41 -04:00
211 changed files with 89913 additions and 80142 deletions

31
.gitignore vendored
View File

@@ -13,22 +13,17 @@ config.sub
configure
depcomp
install-sh
intltool-extract.in
intltool-merge.in
libtool
ltmain.sh
missing
.deps
src/mutter-wm.desktop
src/mutter.desktop
src/metacity-wm.desktop
*.o
*.a
*.lo
*.la
.libs
*.swp
*.gir
*.typelib
tidy-enum-types.[ch]
tidy-marshal.[ch]
stamp-tidy-enum-types.h
@@ -43,18 +38,19 @@ POTFILES
50-metacity-desktop-key.xml
50-metacity-key.xml
inlinepixbufs.h
libmutter.pc
mutter
mutter-theme-viewer
mutter.desktop
mutter.schemas
libmetacity-private.pc
metacity
metacity-dialog
metacity-theme-viewer
metacity.desktop
metacity.schemas
testasyncgetprop
testboxes
testgradient
mutter-grayscale
mutter-mag
mutter-message
mutter-window-demo
metacity-grayscale
metacity-mag
metacity-message
metacity-window-demo
focus-window
test-gravity
test-resizing
@@ -62,8 +58,3 @@ test-size-hints
wm-tester
INSTALL
mkinstalldirs
src/mutter-enum-types.[ch]
src/stamp-mutter-enum-types.h
src/mutter-marshal.[ch]
src/stamp-mutter-marshal.h
src/mutter-plugins.pc

769
NEWS
View File

@@ -1,772 +1,3 @@
3.0.2
=====
* Fix a crash when running without XKB support [Adam]
https://bugzilla.gnome.org/show_bug.cgi?id=647777
* Fix smallish memory leaks [Colin]
https://bugzilla.gnome.org/show_bug.cgi?id=649500
https://bugzilla.gnome.org/show_bug.cgi?id=649504
* Ignore mirrored monitors when listing monitors, fixing
drag-and-drop problems in GNOME Shell [Owen]
https://bugzilla.gnome.org/show_bug.cgi?id=649299
* Don't allow side-by-side tiling of non-maximizable windows
like dialogs and utility windows [Dan]
* Fix interaction of _NET_WM_WINDOW_OPACITY with window effects,
making it work again with GNOME Shell
https://bugzilla.gnome.org/show_bug.cgi?id=648613
Contributors:
Adam Jackson, Colin Walters, Dan Winship
Translations:
Abduxukur Abdurixit [ug]
3.0.1
=====
* If WM_CLIENT_MACHINE isn't set, don't assume a window is remote;
fixes behavior of Fox toolkit applications under GNOME Shell.
https://bugzilla.gnome.org/show_bug.cgi?id=647662 [Colin]
* Fix cases where windows could get stuck drawing as focused after
an attached modal dialog was closed. [Dan]
https://bugzilla.gnome.org/show_bug.cgi?id=647613
* Fix a bug where a window that is too big to be tiled side-by-side
would behave strangely when using the gesture of dragging to
the top to maximize. [Florian]
Contributors:
Florian Müllner, Colin Walters, Dan Winship
Translations:
Amitakhya Phukan [as], Kristjan Schmidt [eo], Muhammet Kara [tr]
3.0.0
=====
* Avoid crashing when you have a single window and try to move it between
workspaces. [Dan]
https://bugzilla.gnome.org/show_bug.cgi?id=642957
Contributors:
Dan Winship
Translations:
Jordi Serratosa [ca], Petr Kovar [cz], Ask H. Larsen [da], Bruce Cowan [en_GB],
Inaki Larranaga Murgoitio [eu], Gabor Kelemen [hu], Dirgita [id], Shankar Prasad [kn],
Changwoo Ryu [ko], Wouter Bolsterlee [nl], Duarte Loreto [pt],
Antonio Fernandes C. Neto, Rodrigo Padula de Oliveira [pt_BR], T. Vasudevan [ta],
Nguyễn Thái Ngọc Duy [vi], Chao-Hsiung Liao [zh_HK, zh_TW]
2.91.93
=======
* Fix bug where, when a monitor was hot-plugged, all workspaces
would collapse to a single workspace. (There are still issues
when a secondary monitor is hot-plugged to the left of the
primary monitor.) [Alex]
https://bugzilla.gnome.org/show_bug.cgi?id=645408)
* Fix a crash for the cycle_group action [Jasper]
https://bugzilla.gnome.org/show_bug.cgi?id=645843
* Fix misdrawing of window shadows on some focus changes [Dan]
https://bugzilla.gnome.org/show_bug.cgi?id=636904
* Export meta_get_replace_current_wm() to allow fixing a
GNOME Shell bug with --replace [Colin]
https://bugzilla.gnome.org/show_bug.cgi?id=645590
Contributors:
Alexander Larsson, Jasper St. Pierre, Colin Walters, Dan Winship
Translations:
Alexander Shopov [bg], Christian Kirbach [de], Yaron Shahrabani [he],
Rudolfs Mazurs [lv], A S Alam [pa], Yuri Myasoedov [ru], Daniel Nylander [se],
Abduxukur Abdurixit [ug], Daniel Korostil [uj], Aron Xu [zh_CN]
2.91.92
=======
* Add a workspaces_only_on_primary preferences. When set, this makes
workspaces switching only apply to windows on the primary monitor,
while windows on other monitors are unaffected.
* Export API for monitor handling [Alex]
MetaScreen::monitors-changed signal
meta_screen_get_primary_monitor()
meta_window_is_on_primary_monitor()
meta_window_get_monitor()
MetaWindow::window-entered-monitor, <etaWindow::window-left-monitor
meta_window_move_to_monitor() [Florian]
* Behavior improvemnts for attached modal dialogs:
- Allow dragging dragging on the titlebar to move the parent ["Ron"]
- Allow resizing [Florian]
- Constrain to be on the current monitor [Florian]
* Don't turn on XSMP autorestart [Colin]
* Combine libmutter-wm and libmutter-private into a single libmutter
[Frédéric]
* Export methods to move and resize windows [Jeffery]
meta_window_move(), meta_window_resize(), meta_window_move_frame()
* Add a MUTTER_WM_CLASS_FILTER environment variable to allow existing
windows to be ignored when performance testing. [Owen]
* Add a new compositor-based flash for visual bell [Dan]
* Fix bug where application specified values for properties like
"skip taskbar" were sometimes ignored [Dan]
* Bug fixes [Dan, Florian, Giovanni, Jasper, Owen]
* Build fixes [Rico]
Contributors:
Giovanni Campagna, Florian Müllner, Alexander Larsson, Jeffery Olson,
Frédéric Péters, Owen Taylor, Jasper St. Pierre, Rico Tzschichholz,
"Ron", Colin Walters, Dan Winship
Translations:
Khaled Hosny [ar], David Planella [ca], Mario Blättermann [de],
Bruce Cowan [en_GB], Jorge González, Daniel Mustieles [es], Ivar Smolin [et],
Bruno Brouard [fr], Fran Diéguez [gl], Yaron Shahrabani [he],
Gabor Kelemen [hu], Luca Ferretti [it], Kjartan Maraas [nb], Piotr Drąg [pl],
Duarte Loreto [pt], Lucian Adrian Grijincu, Adi Roiban [ro],
Yuri Myasoedov [ru], Matej Urbančič [sl], Daniel Korostil [uk]
Bugs fixed:
624360 window shows up in when pressing alt+tab, but skip_taskbar_hint is set to True
631308 Dialogs attached to parent sometimes extend out of the screen
638674 [PATCH] Allow moving attached dialogs
639765 a11y: visual alert only works per-window, not screen
641975 Pre-_NET_WM_ICONs look corrupted
642355 patch to expose MetaWindow.move(), .resize() and add/expose .move_frame() to javascript
642787 MetaWindowActor has a dangling reference to its MetaWindow
643597 Attached dialogs not resizable, even by app request
644188 Broken build of 2.91.91
644252 Add MUTTER_WM_CLASS_FILTER environment variable
644529 session: Change XSMP restart style to Never
644565 Kill libmutter-private ?
644961 auto-tiling makes moving already-tiled windows hard
645224 Translation message doesn't make much sense
645247 Methods of Meta.Rectangle are missing annotations.
645455 tiling: Fix dragging windows free from edge-tiling
2.91.91
=======
* Build a libmutter-wm that contains all of the logic and that
can be linked to to create custom executables. The mutter executable
becomes a small stub linked to this library [Dan]
* Move installed headers files into a meta/ subdirectory instead
of polluting the toplevel namespace [Dan]
* Remove various unused complications: [Dan]
- Ability to set the set of plugins via GConf
- Plugin 'params'
- meta_restart() and "mutter-message restart"
* Don't exit when we are requested to exit via XSMP, assume we'll be
killed along with the X server; this avoids visual artifacts from
unmanaging windows when logging out [Colin]
* Build fixes [Dan, Jani, Jeff]
Contributors:
Jani Monoses, Jeff Olson, Colin Walters, Dan Winship
Translations:
Bruno Brouard [fr], Kjartan Maraas [nb], Daniel Korostil [uk]
Bugs fixed:
643194 patch: expose new meta_window_get_window_rect
643437 Don't exit on XSMP request
643959 Make mutter into a library
2.91.90
=======
* Change <Alt>Above_Tab from being a cycle_group binding to
a switch_group binding [Rui]
* Make plugin-loading failure fatal [Colin]
* Add 'position-changed' signal to MetaWindowActor [Owen]
* When 'live_hidden_previews' is enabled, position hidden windows
to allow the creation of workspace previews [Owen]
* Fix bug with opacity of MetaBackgroundActor
Contributors:
Rui Matos, Owen Taylor, Colin Walters
Translations:
Jorge González [es], Mattias Põldaru [et], Sweta Kothari [gu], Luca Ferretti [it],
Changwoo Ryu [ko], Nguyễn Thái Ngọc Duy [vi]
Bugs fixed:
641309 When live_hidden_previews is set, force placement for hidden windows
641310 MetaWindowActor: Add a 'positioned-changed' signal
641979 Visual glitch on workspace selector closing overview mode
641384 Make plugin loading failure fatal
642426 Don't pass handled key events to GTK+
2.91.6
======
* Add meta_screen_override_window_layout() to let a plugin set the workspace
layout [Owen]
* Add a 'size-changed' signal to MetaWindowActor [Florian]
* Add meta_window_actor_is_destroyed() [Adel]
* Fix problems with window tile previews when cancelling a move [Florian]
* Port theme elements that use GTK+ drawing to use GtkStyleContext instead
of the deprecated GtkStyle. [Florian]
* Fix compiler warnings that were causing compilation failures [Jasper, Owen]
* Misc bug fixes [Gabor, Jasper, Owen, Rui]
Contributors:
Adel Gadllah, Gabor Kelemen, Rui Matos, Florian Müllner, Jasper St. Pierre,
Owen Taylor
Translations:
Khaled Hosny [ar], Alexander Shopov [bg], Petr Kovar [cz], Fran Diéguez [gl],
Marios Zindilis [gr], Gabor Kelemen [hu], Kjartan Maraas [nb], A S Alam [pa],
Daniel Nylander [se], Chao-Hsiung Liao [zh_HK, zh_TW]
2.91.5
======
* Add a Above_Tab key symbol that can be used in key bindings to mean
the key above the Tab key. This is now the default binding for
cycle_group in both Mutter and Metacity. [Owen]
* Add new frame states for tiled-on-the-left and tiled-on-the-right [Florian]
* Add new background drawing functions that can be defined in a theme
for single buttons. [Florian]
* Draw the right button backgrounds for all custom button layouts [Florian]
* Remove vestigal --composite/--no-composite command line options [Nickolas]
* Fix building on GLES [Andreas]
* Code cleanups [Adel, Owen]
Contributors:
Adel Gadllah, Nickolas Lloyd, Andreas Mueller, Florian Müllner, Owen Taylor
Translations:
Mattias Põldaru, Ivar Smolin [et], Gheyret T. Kenji [ug]
Bugs fixed:
613124 Invalid visibility-related asserts in MutterWindow
626875 Fix handling of --composite and --no-composite command line options
629282 [PATCH] Fix errors building for gles-systems (clutter-eglx)
635569 Add an "Above_Tab" pseudo-keysym
635683 add specific button background for single button (per side) case
635686 button backgrounds broken with rtl locales
637330 [PATCH] theme: Add tiled_left/tiled_right frame states
2.91.4
======
* Update for GTK+ 3 changes [Benjamin, Colin, Emmanuele, Florian]
* Support maximizing a window by dragging to the top of the screen
in the same way you can tile by dragging to the edge of the screen.
[Ray, Florian]
* Misc bug fixes [Milan, Owen]
Contributors:
Emmanuele Bassi, Milan Bouchet-Valat, Florian Müllner, Benjamin Otte,
Ray Strode, Owen Taylor, Colin Walters
Translations:
Matej Urbančič [sl], Nguyễn Thái Ngọc Duy [vi]
Bugs fixed:
630548 gnome-shell could auto-maximize windows when dragged to top edge of screen
636083 workspace: Consider text direction when switching
636301 Port testgradient example to GTK3
636302 Replace some GDK X11 calls with future-proof ones
636491 valgrind: meta_window_shape_new (meta-window-shape.c:79)
637802 ui: Adapt to GDK API changes
2.91.3
======
* Better shadows: [Owen]
- Shadows can be different for different window types and focus states
- Shadows are larger by default, especially for the currently active
window
- Shadows for attached modal dialogs and menus are drawn not to
overlap the attachment point.
- Shadows follow the shape of shaped windows
* Optimization: [Owen]
- Avoid repainting in situations when windows are potentially restacked
but aren't actually restacked.
- Pay attention to partial stage repaints in obscured window calculations
- Better optimization of painting obscured shadows; turn off shadows
for maximized windows.
- Move background repainting into Mutter; doing it here rather than
in plugins allows not painting obscured parts of the background.
* A new frame type 'attached' is added for attached modal dialogs
and can be referenced in theme files with a theme version of 3.2.
* Fix updating key bindings when the keyboard layout changes
[Derek, Owen, Thomas]
* Bug fixes [Adel, Florian]
* Build fixes [Dan Williams, Diego, Javier, Owen]
Contributors:
Adel Gadllah, Javier Jardón, Florian Müllner, Derek Poon, Owen Taylor,
Thomas Thurman, Diego Escalante Urrelo, Dan Williams
Translations:
Khaled Hosny [ar], Jorge González [es], Fran Diéguez [gl],
Yaron Shahrabani [he], Kjartan Maraas [nb], Gheyret T. Kenji [ug]
Bugs fixed:
634779 MetaWindowGroup: further optimize paints by using current scissor
634833 Draw the root window background
592382 improve shadow effect
628199 Add antialising to arc and line drawing operations
633002 meta-actor-window: Use G_UNLIKELY for TFP check
634771 MetaStackTracker: Avoid queueing resync for obvious no-ops
635421 Fix crash in check_needs_shadow
635493 configure.in: it's git, not Subversion
635528 configure.ac: move call to AM_GNU_GLIB_GETTEXT above cflags modification
635575 meta-window-actor: remove unused meta_window_actor_get_shadow_bounds
636083 workspace: Consider text direction when switching
2.91.2
======
* Remove support for GTK+ 2 [Florian]
* Adapt to deprecation of size_request deprecation in GTK+ [Matthias]
* Include change from Metacity to fix confusion of mouse
tracking when double-clicking on title bar [Owen]
* Fix bug with the the window menu getting stuck when you alt-Tab [Owen]
Contributors:
Matthias Clasen, Florian Müllner, Owen Taylor
Translations:
Petr Kovar [cz]
Bugs fixed:
633133 Remove compatibility for GTK+-2.0
633352 prepare for the demise of size_request
633398 Fix check for events on UI widgets
633401 Fix warning from synthesized events with GdkDevice
2.91.1
======
* Default build is now GTK+ 3 build
* Mutter namespace prefix is removed, in favor of consistent
meta_ namespace prefixing [Owen]. Naming changes:
MutterWindow => MetaWindowActor
mutter_get_windows => meta_get_window_actors
mutter_plugin_get_windows => meta_plugin_get_window_actors
* Add missing values in MetaKeyBindingAction - this fixes a problem where
key binding lookup wasn't working properly for some key bindings. [Dan]
* Remove keysym parameter to meta_display_get_keybinding_action() - the
function expected the default keysym for the keycode to always be passed [Dan]
* Clean up installed header files - in particular, theme-parser.h is merged
into a new public-only theme.h and private internals are moved to
theme-private.h.
* Fix problems with antialiased rendering of themes [Brandon, Owen, Nickolas]
* Fix problem with parsing color constants in themes [Jon, Owen]
* Build fixes [Colin]
* Miscellaneous bug fixes [Giovanni, Rico]
Contributors:
Giovanni Campagna, Nickolas Lloyd, William Jon McCann, Owen Taylor,
Rico Tzschichholz, Colin Walters, Dan Winship, Brandon Wright
Translations:
Fran Diéguez [gl], Yinghua Wang [zh_CN]
Fixed bugs:
628401 tint and line draw ops rendering issues
628520 unfortunate namespacing
631487 Fix drawing of <arc> theme elements
632116 don't clobber gerrors
632149 Fill in missing MetaKeyBindingAction values
632155 meta_display_get_keybinding_action: remove keysym parameter
632474 Remove MetaRegion
632494 introspection: remove --allow-unprefixed
2.91.0
======
* Enable side-by-side tiling via a gesture of dragging to the left or right
edge of the screen. (enabled with an off-by-default GConf key) [Florian]
* Allow breaking out of maximization/tiling using a alt-middle-button window
resize [Owen, Florian]
* Add the ability to have modal dialogs attached to their parent window
(enabled with an off-by-default GConf key) [Maxim]
* Draw with Cairo rather than GDK [Florian, Benjamin]
* Add compatibility for changes in GTK+ 3
[Benjamin, Alban, Florian, Jasper, Matthias, Owen, Thierry]
- libmutter-private is now only installed for GTK+ 3 builds
- Theme parts of libmutter-private API are changed to take cairo_t
rather than GdkDrawable
* Update introspection build and annotations for new behavior of
g-ir-scanner [Colin]
* Fix bug that caused window menu options not to work [Owen]
* Fix misbehavior of Wine windows [Owen, Alban]
* Fix crashes from missing error traps [Adel]
* Build fixes [Colin, Florian, Owen, Rob, Tomas]
* Misc bug fixes [Adel, Jon, Owen, Nickolas, Tomas]
* Cleanups [Adel, Benjamin, Florian]
Contributors:
Alban Browaeys, Matthias Clasen, Maxim Ermilov, Tomas Frydrych, Adel Gadllah,
Nickolas Lloyd, William Jon McCann, Florian Muellner, Benjamin Otte,
Thierry Reding, Rob Staudinger, Jasper St. Pierre, Owen Taylor, Colin Walters
Translations:
Alexander Shopov [bg], Mario Blättermann [de], Ask H. Larsen [dk],
Michael Kotsarinis [el], Philip Withnall [en_UK], Jorge González [es],
Fran Diéguez [gl], Bruno Brouard, Claude Paroz [fr], Yaron Shahrabani [he],
Gabor Kelemen [hu], Luca Ferretti [it], Nils-Christoph Fiedler [nds],
Kjartan Maraas [nb], A S Alam [pa], Piotr Drąg [pl], Duarte Loreto [pt],
Antonio Fernandes C. Neto [pt_BR], Matej Urbančič [sl],
Miloš Popović [sr, sr@latin], Tirumurti Vasudevan [ta], Aron Xu [zh_CN],
Chao-Hsiung Liao [zh_HK, zh_TW]
Fixed Bugs:
597763 With >2 workspaces, Window menu "Move to Another Workspace" menu doesn't work
598603 displays window size when moving terminal window
606158 "Always on top" triggers Window manager warning:
Log level 8: meta_window_set_user_time: assertion `!window->override_redirect' failed
610575 make meta_screen_set_cursor public
613126 Do not cancel Alt+Tab grab due to Shift key events
623235 BadDamage error from XSubtractDamage
624757 Check for TFP usage after actually setting the pixmap
625712 [mutter-shaped-texture] Remove material_workaround
626583 Replace Gdk drawing API with cairo
627087 Mipmap emulation not working
627210 Crash with X error
628544 introspection: Build with --warn-fatal, drop fix-meta-rectangle.py hack
629127 build problem with recent gtk3
629232 Multiple syntax errors in file mutter-message.c when building Mutter for
GNOME Shell dependencies
629350 [mutter-shaped-texture] Use a base material for all instances
629931 Allow breaking out from maximization/tiling during a mouse resize
630195 Use GDK error trapping straight-up
630203 Prepare mutter code for GTK3 rendering-cleanup
630671 prepare mutter for the demise of GtkObject
630843 gtk_window_set_visual was replaced by gtk_widget_set_visua
631147 Adapt to GTK API changes
631175 Mutter error compiling Gnome Shell
2.31.5
======
* Support building with GTK+ 3.0 [Florian]
* Remove deprecated usages for compatibility with GTK+ 3.0
[Claudio, Florian, Nickolas]
* Export a boxed type for MetaRectangle [Owen]
* Allow disabling -Werror with --enable-compile-warnings=yes [Nickolas]
* Build fixes [Andreas, Florian, Owen]
Contributors:
Nickolas Lloyd, Andreas Mueller, Florian Müllner, Claudio Saavedra,
Owen Taylor
Translations:
Petr Kovar [cz], Jorge González [es], Fran Diéguez [gl],
Yaron Shahrabani [he], Matej Urbančič [sl]
Fixed Bugs:
587991 - Remove deprecated GTK+ symbols
616275 - -Werror should not be enabled by default (or should be possible to disable)
622303 - Allow building with Gtk+-3.0
622800 - Make mutter more gtk+ 3.0 friendly
623335 - Make MetaRectangle a boxed type
623639 - Work around g-ir-scanner problem with Gdk.Rectangle
624166 - src/core/util.c: Fix warning in case WITH_VERBOSE_MODE is not set
2.31.4
======
* Clean up MutterPlugin effect interface [Maxim]
* Track damage as the bounding box, a significant optimizations
for rapidly drawing clients [Robert]
* Add meta_window_is_remote() [Colin]
* Add meta_add_debug_topic() for turning on logging of
specific topics [Colin]
* Fix bug with window unmaximization [Owen]
Contributors:
Robert Bragg, Maxim Ermilov, Owen Taylor, Colin Walters
Translations:
Yaron Shahrabani (he), Fran Diéguez (gl), Kjartan Maraas (nb), A S Alam (pa)
Fixed Bugs:
611838 - expose sub-stage redraws by streaming raw updates to ClutterX11TexturePixmap
620585 - Add meta_window_is_remote
620860 - function meta_display_open
621082 - MutterPluginManager should call plugin->switch_workspace,
when screen doesn't have any window. Or function should be renamed.
621413 - Maximize/Unmaximize not behaving properly for some non-gnome based programs
2.31.2
======
* Theme enhancements [Owen]
- Add a flexible version mechanism for themes -
metacity-theme-3.xml is now supported, and can include
version="> 3.2" type attributes on the root element or
any subelement.
- Add frame_x_center/frame_y_center variables
- Allow a theme to turn on title ellipsization
* Performance enhancements:
- Stream raw damage updates to ClutterX11TexturePixmap
to enable partial stage updates when windos change [Robert]
- Don't trap XErrors in meta_compositor_process_event [Adel]
* Add meta_prefs_override_preference_location(); this allows
a plugin like GNOME Shell to redirect preferences to a
plugin-specific location. [Owen]
* Support a _MUTTER_HINTS window property; this is a string
property holding key-value pairs with plugin-specific
interpretation [Tomas]
* Build with GSEAL_ENABLE [Florian, Javier]
* Add meta_display_get_leader_window() [Tomas]
* Add meta_display_sort_windows_by_stacking [Colin]
* Export
meta_display_get_last_user_time()
meta_display_xserver_time_is_before()
meta_window_foreach_ancestor(),
meta_window_foreach_transient()
meta_window_lower()
meta_window_raise()
meta_window_set_demands_attention()
meta_window_unset_demands_attention() [Colin]
* Bug fixes [Dan, Edward, Owen, Tomas]
* Build fixes [Owen, Dominique, Vincent]
Contributors:
Robert Bragg, Adel Gadllah, Tomas Frydrych, Javier Jardón,
Dominique Leuenberger, Florian Müllner, Edward Sheldrake,
Owen Taylor, Vincent Untz, Colin Walters, Dan Winship
Translations:
Xandru Armesto Fernandez (ast), Khaled Hosny (ar), Petr Kovar (cz),
Mario Blättermann, (de), Jorge González (es),
Inaki Larranaga Murgoitio [eu), Claude Paroz (fr), Luca Ferretti (it),
Gintautas Miliauskas (lt), Pavol Šimo (sk), Matej Urbančič (sl)
Fixed Bugs:
591842 - ellipsize titles when oversize
592503 - Add a flexible version mechanism
595496 - Use accessor functions instead direct access (use GSEAL GnomeGoal)
596659 - Fix handling of grabbed key events
613123 - Framework for plugin-specific per-window hint
613125 - Add meta_display_get_leader_window()
613127 - Keep num_workspaces key in sync with the actual workspace number
613136 - remove over-restrictive assert from meta_prefs_get_workspace_name()
613398 - Don't trap XErrors in meta_compositor_process_event
615586 - Allow redirecting preferences to a different GConf key
615672 - cant' compile mutter error: dereferencing pointer p does break
strict-aliasing rules
616050 - alt-tab infrastructure patches
616274 - mutter from git fails with gcc 4.5 (on new warning)
616546 - On dual screen maximized windows dragged to the second screen no
longer update their contents
618138 - Work around COGL bug causing flash for new windows
618613 - Fix crash with --sync option
2.29.1
======
* Support and require Clutter 1.2 (Owen)
* Add meta_display_get_keybinding_action() (Colin, Dan)
* Add meta_window_get_wm_class_instance() (Tomas)
* Remove workaround for bug fixed in intel driver Q2/2009 release (Robert)
* Build fixes (Owen, Brian, Nguyễn Thái Ngọc Duy)
Contributors:
Robert Bragg, Brian Cameron, Tomas Frydrych, Nguyễn Thái Ngọc Duy,
Owen Taylor, Colin Walters, Dan Winship
Translations:
Alexander Shopov (bg), Mario Blättermann (de), Bruno Brouard (fr),
Nils-Christoph Fiedler (nds), Piotr Drąg (pl), Aron Xu (zh_CN)
Fixed Bugs:
610862 Support and require Clutter 1.1
612506 mutter 2.29.0 fails to compile on Solaris
613100 [MetaDisplay] Expose meta_display_get_keybinding_action
613121 Remove workaround for multitexturing with old intel drivers
613128 [MetaWindow] Accessor for the instance part of WM_CLASS property
613278 meta_display_get_keybinding_action: strip out uninteresting modifiers
2.29.0
======
* Improve appearance of scaled down windows using mipmap emulation (Owen)
* Added signals: MetaDisplay::window-created, MetaDisplay::window-marked-urgent,
MetaDisplay::window-demands-attention, MetaWindow::unmanaged (Colin, Tomas)
* Added properties: MetaWindow:demands-attention, MetaWindow:urgent,
MetaWindow:maximized-horizontally, MetaWindow:maximized-vertically (Florian, Tomas)
* Fix nasty crash when workspace "struts" changed during a window move (Jon, Owen)
* Bug fixes (Dan, Maxim, Neil, Owen, Tomas)
* Build fixes (Colin, Emmanuele, Nickolas, Owen, Richard)
* Merge Metacity changes since 2.26. Includes themable sound support
via libcanberra (Owen)
Contributors
Emmanuele Bassi, Maxim Ermilov, Tomas Frydrych, Richard Hughes, Nickolas Lloyd,
Florian Müllner, Jon Nettleton, Neil Roberts, Owen Taylor, Colin Walters,
Dan Winship
Additional Metacity contributors:
Thomas Hindoe Paaboel Andersen, Peter Bloomfield, Matthias Clasen,
Matt Kraai, Claude Paroz, Lennart Poettering, Ray Strode, Thomas Thurman,
Vincent Untz, Tomislav Vujec, Tomeu Vizoso, Travis Watkins, 'alexisdm59'
Translations:
Khaled Hosny (ar), Petr Kovar (cz), Kjartan Maraas (nb), Djavan Fagundes (pt_BR),
Nils-Christoph Fiedler (nds), Matej Urbančič (sl), Vincent Untz
Fixed Bugs:
588065 Adds demands-attention signal to the window class
591913 Fails to skip current window on alt+tab when another window is asking for attention
592567 Dereferencing NULL in mutter_window_get_workspace()
597052 Add signal to MetaDisplay so we know when a window has demanded-attention
598289 Add "window-created" signal to MetaDisplay, "unmanaged" signal for MetaWindow
598473 "XXX specified twice for this theme" messages not in sync with metacity.
598600 "Visual Bell" option in Metacity causes Mutter to crash
600068 notifications for window urgency hint
601228 rdesktop does not get keypress signals
602349 [PATCH] trivial - fix compilation warning in mutter
602740 Remove XOR gc only used in removed reduced-resources mode
602870 Fix compilation with older libGL
604200 Compile issue: Use of deprecated clutter functions
606388 mutter fails to build when using ld with --no-add-needed
607125 Fails to build with latest introspection data
607398 Do not use CGL_* symbols
607746 reduce gconf roundtrips at startup
608800 alt-dragging gimp windows crashes gnome-shell
609350 Mutter does not support the COGL_DEBUG environment variable
609546 meta_workspace_set_builtin_struts(): optimize out non-changes
609585 Merge libcanberra usage from Metacity
609657 Use cogl multitexture API when drawing MutterShapedTexture
609665 Bug fixes from Fedora RPM
609710 screencast recording broke
610391 Fix crash on startup with list bindings
2.28.0
======
* New exported API:
meta_window_get_stable_sequence() [Colin]
meta_window_get_transient_for_as_xid() [Tomas]
MutterScreen::workareas-changed signal [Tomas]
* Fix a problem where changes processed from a Clutter event
callback wouldn't get handled before the screen was next
repainted, causing flashing [Owen]
* Remove MetaAltTabHandler as no longer needed [Dan]
* Bug fixes [Colin, Owen]
Contributors:
Tomas Frydrych, Owen Taylor, Colin Walters, Dan Winship
Translations:
Christian Kirbach (de), Claude Paroz (fr)
2.27.5
======
* Fix bug in GConf schemas where the overview activation key was specified as
'<Super_L>' not 'Super_L'.
Contributors:
Colin Walters
Translation:
Denis Arnaud (br)
2.27.4
======
* Big code cleanup: when talking about multiple monitors, call them
"monitors", not "xineramas". [Dan]
* Accessors added or made public:
meta_screen_get_n_monitors(), meta_screen_get_monitor_geometry()
meta_window_get_user_time() and MetaWindow:user-time property.
[Colin, Dan]
* Set _GNOME_WM_KEYBINDINGS=Metacity,Mutter on the _NET_SUPPORTING_WM_CHECK
window so that gnome-keybinding-properties can figure out to show the
Metacity keybindings when Mutter is running. [Owen]
* Bug and build fixes [Colin, Owen]
Contributors:
Owen Taylor, Colin Walters, Dan Winship
Translation:
Jorge González (es), Inaki Larranaga Murgoitio (eu), Gabor Kelemen (hu)
Bugs fixed:
592393 - Clicking on a minimized window in the overview doesn't focus the window
593399 - Add meta_display_get_grab_op()
593404 - Make MUTTER_DEBUG_XINERAMA override active Xinerama
593407 - Add 'skip-taskbar' accessor to MetaWindow.
593686 - Add meta_screen_get_monitors()
594067 - Export a _GNOME_WM_KEYBINDINGS property
2.27.3
======
* Key handling improvements:
- enforce that every key is handled no more than once.
- mutter_plugin_begin_modal() and mutter_plugin_begin_modal() allow
putting a plugin into a "modal" state where it has exclusive access
to key and pointer events.
- Add "tab_popup_select", "tab_pop_cancel" pseudo-keypress-handlers
that plugins can use to get notification when Alt-Tab ends
[Owen]
* Accessors added or made public:
meta_window_is_override_redirect(), meta_window_is_mapped(),
meta_display_xwindow_is_a_no_focus_window(),
meta_display_get_grab_op(), meta_window_is_skip_taskbar(),
meta_window_is_modal(), all of errors.h
[Colin, Owen, Michael, Steve, Tomas]
* Fix for various GTK+ deprecations [Javier]
* Bug fixes [Colin, Frédéric, Owen, Thomas, Tomas, Volker]
Contributors:
Javier Jardón, Steve Frécinaux, Tomas Frydrych, Michael Meeks,
Frédéric Péters, Volker Sobek, Owen Taylor, Thomas Thurman,
Colin Walters
Translation:
Fran Dieguez (gl), Gabor Kelemen (hu), Daniel Nylander (se)
Bugs fixed:
589457 - Fix up window property notification for "title"
590911 - Do not run plugin effects on WM startup
590978 - API to query whether window is in modal state
591367 - Be silent by default
591566 - install errors.h header ...
591788 - Add meta_window_is_override_redirect
591836 - mutter mishandles opacity
591913 - Fails to skip current window on alt+tab when another window is asking for attention
592393 - Clicking on a minimized window in the overview doesn't focus the window
592699 - Remove deprecated Encoding key from desktop files
592742 - Avoid accessing freed memory when being replaced
593399 - Add meta_display_get_grab_op()
593404 - Make MUTTER_DEBUG_XINERAMA override active Xinerama
593407 - Add 'skip-taskbar' accessor to MetaWindow.
----------------------------- Older Metacity News -----------------------------
2.26.0
======

2
README
View File

@@ -20,7 +20,7 @@ libstartup-notification at
http://www.freedesktop.org/software/startup-notification/ or on the
GNOME ftp site. You also need GConf 1.2 (unless building a funky
extra-small embedded metacity with --disable-gconf, see below).
You need Clutter 1.0. You need gobject-introspection 0.6.3.
You need Clutter 0.9.3. You need gobject-introspection 0.6.3.
REPORTING BUGS AND SUBMITTING PATCHES
===

View File

@@ -1,13 +1,15 @@
AC_PREREQ(2.50)
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [0])
m4_define([mutter_micro_version], [2])
m4_define([mutter_major_version], [2])
m4_define([mutter_minor_version], [27])
# Fibonacci sequence for micro version numbering:
# 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987
m4_define([mutter_micro_version], [0])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
m4_define([mutter_plugin_api_version], [3])
m4_define([mutter_plugin_api_version], [2])
AC_INIT([mutter], [mutter_version],
[http://bugzilla.gnome.org/enter_bug.cgi?product=mutter])
@@ -15,8 +17,7 @@ AC_INIT([mutter], [mutter_version],
AC_CONFIG_SRCDIR(src/core/display.c)
AC_CONFIG_HEADERS(config.h)
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
AM_INIT_AUTOMAKE
AM_MAINTAINER_MODE
MUTTER_MAJOR_VERSION=mutter_major_version
@@ -45,9 +46,6 @@ AC_HEADER_STDC
AC_LIBTOOL_WIN32_DLL
AM_PROG_LIBTOOL
# Sets GLIB_GENMARSHAL and GLIB_MKENUMS
AM_PATH_GLIB_2_0()
#### Integer sizes
AC_CHECK_SIZEOF(char)
@@ -61,11 +59,70 @@ AC_CHECK_SIZEOF(__int64)
## byte order
AC_C_BIGENDIAN
GTK_MIN_VERSION=2.91.7
CANBERRA_GTK=libcanberra-gtk3
CANBERRA_GTK_VERSION=0.26
#### Warnings
MUTTER_PC_MODULES="gtk+-3.0 >= $GTK_MIN_VERSION pango >= 1.2.0 cairo >= 1.10.0"
changequote(,)dnl
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 "x$enable_ansi" = "xyes"; then
case " $CFLAGS " in
*[\ \ ]-ansi[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -ansi" ;;
esac
case " $CFLAGS " in
*[\ \ ]-pedantic[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -pedantic" ;;
esac
fi
fi
changequote([,])dnl
MUTTER_PC_MODULES='gtk+-2.0 >= 2.10.0 pango >= 1.2.0'
AC_ARG_ENABLE(gconf,
AC_HELP_STRING([--disable-gconf],
@@ -96,16 +153,31 @@ AC_ARG_ENABLE(startup-notification,
[disable mutter's startup notification support, for embedded/size-sensitive custom non-GNOME builds]),,
enable_startup_notification=auto)
AC_ARG_WITH(libcanberra,
AC_HELP_STRING([--without-libcanberra],
[disable the use of libcanberra for playing sounds]),,
with_libcanberra=auto)
AC_ARG_ENABLE(compositor,
AC_HELP_STRING([--disable-compositor],
[disable mutter's compositing manager]),,
enable_compositor=auto)
AC_ARG_ENABLE(clutter,
AC_HELP_STRING([--without-clutter],
[disable the use of clutter for compositing]),,
with_clutter=auto)
AC_ARG_ENABLE(introspection,
AC_HELP_STRING([--without-introspection],
[disable the use of GObject introspection]),,
with_introspection=auto)
AC_ARG_ENABLE(xsync,
AC_HELP_STRING([--disable-xsync],
[disable mutter's use of the XSync extension]),,
enable_xsync=auto)
AC_ARG_ENABLE(render,
AC_HELP_STRING([--disable-render],
[disable mutter's use of the RENDER extension]),,
enable_render=auto)
AC_ARG_ENABLE(shape,
AC_HELP_STRING([--disable-shape],
[disable mutter's use of the shaped window extension]),,
@@ -117,11 +189,17 @@ AC_CHECK_HEADERS(execinfo.h, [AC_CHECK_FUNCS(backtrace)])
AM_GLIB_GNU_GETTEXT
## here we get the flags we'll actually use
# GRegex requires Glib-2.14.0
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0)
# gtk_window_set_icon_name requires gtk2+-2.6.0
PKG_CHECK_MODULES(MUTTER_MESSAGE, gtk+-3.0 >= $GTK_MIN_VERSION)
PKG_CHECK_MODULES(MUTTER_WINDOW_DEMO, gtk+-3.0 >= $GTK_MIN_VERSION)
# GOptionEntry requires glib-2.6.0
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.6.0)
# gtk_window_set_icon_name requires gtk2+-2.60
PKG_CHECK_MODULES(MUTTER_MESSAGE, gtk+-2.0 >= 2.6.0)
PKG_CHECK_MODULES(MUTTER_WINDOW_DEMO, gtk+-2.0 >= 2.6.0)
if $PKG_CONFIG --atleast-version 1.2.0 pangoxft; then
echo "pangoxft found"
else
AC_MSG_ERROR("Pango 1.2.0 or greater based on Xft2 is required")
fi
# Unconditionally use this dir to avoid a circular dep with gnomecc
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
@@ -153,28 +231,43 @@ else
echo "Building without libstartup-notification"
fi
have_libcanberra=no
AC_MSG_CHECKING([libcanberra-gtk])
if test x$with_libcanberra = xno ; then
AC_MSG_RESULT([disabled])
else
if $PKG_CONFIG --exists $CANBERRA_GTK '>=' $CANBERRA_GTK_VERSION; then
have_libcanberra=yes
AC_MSG_RESULT(yes)
MUTTER_PC_MODULES="$MUTTER_PC_MODULES $CANBERRA_GTK"
AC_DEFINE([HAVE_LIBCANBERRA], 1, [Building with libcanberra for playing sounds])
else
AC_MSG_RESULT(no)
if test x$with_libcanberra = xyes ; then
AC_MSG_ERROR([libcanberra forced and libcanberra-gtk was not found])
fi
fi
fi
## init this, it gets set either in the compositor check below
## or the render-specific check later
have_xrender=no
XCOMPOSITE_VERSION=0.2
if test x$enable_compositor = xyes; then
have_xcomposite=yes
elif test x$enable_compositor = xauto; then
echo "Building compositing manager by default now."
have_xcomposite=yes
else
have_xcomposite=no
fi
AC_MSG_CHECKING([Xcomposite >= $XCOMPOSITE_VERSION])
if $PKG_CONFIG --atleast-version $XCOMPOSITE_VERSION xcomposite; then
if test x$with_clutter = xyes; then
have_xcomposite=yes
have_clutter=yes
elif test x$with_clutter = xauto; then
echo "Building clutter compositing manager by default now."
have_xcomposite=yes
have_clutter=yes
else
have_clutter=no
fi
AM_CONDITIONAL(WITH_CLUTTER, test "$have_clutter" = "yes")
if test x$have_xcomposite = xyes; then
AC_MSG_CHECKING([Xcomposite >= $XCOMPOSITE_VERSION])
if $PKG_CONFIG --atleast-version $XCOMPOSITE_VERSION xcomposite; then
AC_MSG_RESULT([yes])
else
AC_MSG_ERROR([no. Use --disable-compositor to disable.])
fi
fi
if test x$have_xcomposite = xyes; then
MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcomposite >= $XCOMPOSITE_VERSION xfixes xrender xdamage"
AC_DEFINE(HAVE_COMPOSITE_EXTENSIONS, 1, [Building with compositing manager support])
echo "Building with compositing manager"
@@ -182,13 +275,42 @@ if $PKG_CONFIG --atleast-version $XCOMPOSITE_VERSION xcomposite; then
## force on render also
have_xrender=yes
else
AC_MSG_ERROR([no. Mutter requires the Xcomposite extension to build.])
echo "Building without compositing manager"
fi
CLUTTER_VERSION=1.2.0
CLUTTER_PACKAGE=clutter-1.0
## if no compositor, still possibly enable render
if test x$have_xcomposite = xno; then
XRENDER_VERSION=0.0
AC_MSG_CHECKING([xrender >= $XRENDER_VERSION])
if $PKG_CONFIG --atleast-version $XRENDER_VERSION xrender; then
have_xrender=yes
else
have_xrender=no
fi
AC_MSG_RESULT($have_xrender)
if test x$enable_render = xyes; then
have_xrender=yes
echo "Render support forced on"
elif test x$enable_render = xauto; then
true
else
have_xrender=no
fi
if test x$have_xrender = xyes; then
echo "Building with Render"
MUTTER_PC_MODULES="$MUTTER_PC_MODULES xrender >= $XRENDER_VERSION"
fi
fi ## have_composite
if test x$have_xrender = xyes; then
AC_DEFINE(HAVE_RENDER, , [Building with Render extension support])
fi
CLUTTER_PACKAGE=clutter-0.9
AC_SUBST(CLUTTER_PACKAGE)
if $PKG_CONFIG --atleast-version $CLUTTER_VERSION $CLUTTER_PACKAGE ; then
if test x$have_clutter = xyes; then
MUTTER_PC_MODULES="$MUTTER_PC_MODULES $CLUTTER_PACKAGE "
PKG_CHECK_MODULES(CLUTTER, $CLUTTER_PACKAGE)
AC_DEFINE(WITH_CLUTTER, , [Building with Clutter compositor])
@@ -205,19 +327,26 @@ if $PKG_CONFIG --atleast-version $CLUTTER_VERSION $CLUTTER_PACKAGE ; then
AC_DEFINE(HAVE_GLX_TEXTURE_PIXMAP, ,
[Is ClutterGLXTexturePixmap available?])
fi
else
AC_MSG_ERROR([no. Mutter requires Clutter version $CLUTTER_VERSION.])
fi
INTROSPECTION_VERSION=0.9.5
GOBJECT_INTROSPECTION_CHECK([$INTROSPECTION_VERSION])
if test x$found_introspection != xno; then
AC_DEFINE(HAVE_INTROSPECTION, 1, [Define if GObject introspection is available])
MUTTER_PC_MODULES="$MUTTER_PC_MODULES gobject-introspection-1.0"
META_GIR=[Meta_]mutter_major_version[_]mutter_minor_version[_gir]
AC_SUBST(META_GIR)
if test x$with_introspection != xno; then
PKG_CHECK_MODULES(INTROSPECTION, gobject-introspection-1.0, have_introspection=yes, have_introspection=no)
if test x$have_introspection=xyes; then
MUTTER_PC_MODULES="$MUTTER_PC_MODULES gobject-introspection-1.0"
AC_DEFINE(HAVE_INTROSPECTION, 1, [Define if GObject introspection is available])
G_IR_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0`
AC_SUBST(G_IR_SCANNER)
G_IR_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0`
AC_SUBST(G_IR_COMPILER)
G_IR_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0`
AC_SUBST(G_IR_GENERATE)
GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0`
AC_SUBST(GIRDIR)
TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)"
AC_SUBST(TYPELIBDIR)
fi
fi
AM_CONDITIONAL(WITH_INTROSPECTION, test "$have_introspection" = "yes")
AC_MSG_CHECKING([Xcursor])
if $PKG_CONFIG xcursor; then
@@ -364,7 +493,7 @@ fi
MUTTER_LIBS="$MUTTER_LIBS $XSYNC_LIBS $RANDR_LIBS $SHAPE_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm"
MUTTER_MESSAGE_LIBS="$MUTTER_MESSAGE_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
MUTTER_WINDOW_DEMO_LIBS="$MUTTER_WINDOW_DEMO_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm"
MUTTER_WINDOW_DEMO_LIBS="$MUTTER_WINDOW_DEMO_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
MUTTER_PROPS_LIBS="$MUTTER_PROPS_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
found_sm=no
@@ -432,88 +561,24 @@ if test "x$enable_debug" = "xyes"; then
CFLAGS="$CFLAGS -g -O"
fi
# For fix-meta-rectangle.py
AM_PATH_PYTHON([2.5])
# Warnings are there for a reason
if test "x$GCC" = "xyes"; then
CFLAGS="$CFLAGS -Wall -Werror -ansi"
fi
# 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
doc/man/Makefile
src/Makefile
src/wm-tester/Makefile
src/libmutter.pc
src/libmutter-private.pc
src/mutter-plugins.pc
src/tools/Makefile
src/compositor/plugins/Makefile
src/compositor/mutter/plugins/Makefile
po/Makefile.in
])
@@ -536,7 +601,7 @@ fi
dnl ==========================================================================
echo "
mutter-$VERSION
mutter-$VERSION:
prefix: ${prefix}
source code location: ${srcdir}
@@ -546,21 +611,23 @@ mutter-$VERSION
XFree86 Xinerama: ${use_xfree_xinerama}
Solaris Xinerama: ${use_solaris_xinerama}
Startup notification: ${have_startup_notification}
libcanberra: ${have_libcanberra}
Introspection: ${found_introspection}
Compositing manager: ${have_xcomposite}
Introspection: ${have_introspection}
Session management: ${found_sm}
Shape extension: ${found_shape}
Resize-and-rotate: ${found_randr}
Xsync: ${found_xsync}
Render: ${have_xrender}
Xcursor: ${have_xcursor}
Clutter: ${have_clutter}
"
MUTTER_MINOR_VERSION=mutter_minor_version
if expr $MUTTER_MINOR_VERSION % 2 > /dev/null ; then
stable_version=`expr $MUTTER_MINOR_VERSION - 1`
if test $(( $(echo $MUTTER_MINOR_VERSION) %2)) == "1"; then
stable_version=$(( ($MUTTER_MINOR_VERSION / 2) * 2))
echo "This is the UNSTABLE branch of mutter"
echo -n "Use 2.$stable_version.x for stable "
echo "(gnome-2-$stable_version branch in git)"
echo "(gnome-2-$stable_version branch in Subversion)"
else
echo "This is the stable branch of mutter"
fi

View File

@@ -4,7 +4,6 @@ of the theme format, and a given theme can support more than one format.
Version 1: THEMEDIR/metacity-1/metacity-theme-1.xml
(original metacity format)
Version 2: THEMEDIR/metacity-1/metacity-theme-2.xml
Version 3: THEMEDIR/metacity-1/metacity-theme-3.xml
The subdirectory name is "metacity-1" in all versions.
@@ -22,59 +21,6 @@ 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
========================================
Additional predefined variables are added for positioning expressions:
frame_x_center: the X center of the entire frame, with respect to the
piece currently being drawn.
frame_y_center: the Y center of the entire frame, with respect to the
piece currently being drawn.
The <title/> element now supports an "ellipsize_width" attribute. When
specified, this gives a width at which to ellipsize the title. If not
specified, the title will simply be clipped to the title area.
New Features in Theme Format Version 3
======================================
Format version 3 has exactly one new feature; any element in the file
can now have a version attribute:
version="[<|<=|=>|>] MAJOR.MINOR"
(< and > should be to be entity escaped as &lt; and &gt;). If this
version check is not met, then the element and its children will be
ignored. This allows having alternate sections of the theme file for
older and newer version of the Metacity theme format.
When placed on the toplevel <metacity_theme> element, an unsatisfied
version check will not just cause the contents of the file to be
ignored, it will also cause the lookup of a theme file to proceed on
and look for an older format 2 or format 1 file. This allows making a
metacity-theme-3.xml file that is only used the format version 3.2 or
newer is supported, and using metacity-theme-1.xml for older window
managers.
New Features in Theme Format Version 2
======================================

View File

@@ -6,16 +6,6 @@
<name xml:lang="en">mutter</name>
<shortdesc xml:lang="en">Window and compositing manager based on Clutter</shortdesc>
<description>Mutter is a window and compositing manager that displays and
manages your desktop via OpenGL. Mutter combines a sophisticated display engine
using the Clutter toolkit with solid window-management logic inherited from the
Metacity window manager.
While Mutter can be used stand-alone, it is primarily intended to be used as
the display core of a larger system such as GNOME Shell. For this reason,
Mutter is very extensible via plugins, which are used both to add fancy visual
effects and to rework the window management behaviors to meet the needs of the
environment.</description>
<!--
<homepage rdf:resource="http://www.gnome.org/" />
-->

View File

@@ -10,7 +10,6 @@ be@latin
bg
bn
bn_IN
br
bs
ca
ca@valencia
@@ -22,7 +21,6 @@ dz
el
en_CA
en_GB
eo
es
et
eu
@@ -58,7 +56,6 @@ mn
mr
ms
nb
nds
ne
nl
nn
@@ -83,7 +80,6 @@ te
th
tk
tr
ug
uk
vi
wa

View File

@@ -1,14 +1,11 @@
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
src/core/all-keybindings.h
src/core/bell.c
src/core/core.c
src/core/delete.c
src/core/display.c
src/core/errors.c
src/core/keybindings.c
src/core/main.c
src/core/mutter.c
src/core/prefs.c
src/core/screen.c
src/core/session.c
@@ -16,6 +13,7 @@ src/core/util.c
src/core/window.c
src/core/window-props.c
src/core/xprops.c
src/include/all-keybindings.h
src/mutter.desktop.in
src/mutter-wm.desktop.in
src/mutter.schemas.in

3704
po/ar.po

File diff suppressed because it is too large Load Diff

2175
po/as.po

File diff suppressed because it is too large Load Diff

1825
po/ast.po

File diff suppressed because it is too large Load Diff

2093
po/bg.po

File diff suppressed because it is too large Load Diff

1835
po/br.po

File diff suppressed because it is too large Load Diff

3126
po/ca.po

File diff suppressed because it is too large Load Diff

2032
po/cs.po

File diff suppressed because it is too large Load Diff

2505
po/da.po

File diff suppressed because it is too large Load Diff

3594
po/de.po

File diff suppressed because it is too large Load Diff

1535
po/el.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1826
po/eo.po

File diff suppressed because it is too large Load Diff

3052
po/es.po

File diff suppressed because it is too large Load Diff

2944
po/et.po

File diff suppressed because it is too large Load Diff

2030
po/eu.po

File diff suppressed because it is too large Load Diff

3637
po/fr.po

File diff suppressed because it is too large Load Diff

3791
po/gl.po

File diff suppressed because it is too large Load Diff

1540
po/gu.po

File diff suppressed because it is too large Load Diff

3365
po/he.po

File diff suppressed because it is too large Load Diff

2049
po/hu.po

File diff suppressed because it is too large Load Diff

4977
po/id.po

File diff suppressed because it is too large Load Diff

2861
po/it.po

File diff suppressed because it is too large Load Diff

5604
po/kn.po

File diff suppressed because it is too large Load Diff

3280
po/ko.po

File diff suppressed because it is too large Load Diff

1677
po/lt.po

File diff suppressed because it is too large Load Diff

2794
po/lv.po

File diff suppressed because it is too large Load Diff

2009
po/nb.po

File diff suppressed because it is too large Load Diff

1814
po/nds.po

File diff suppressed because it is too large Load Diff

2081
po/nl.po

File diff suppressed because it is too large Load Diff

2732
po/pa.po

File diff suppressed because it is too large Load Diff

3553
po/pl.po

File diff suppressed because it is too large Load Diff

2638
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2839
po/ro.po

File diff suppressed because it is too large Load Diff

3650
po/ru.po

File diff suppressed because it is too large Load Diff

2118
po/sk.po

File diff suppressed because it is too large Load Diff

3152
po/sl.po

File diff suppressed because it is too large Load Diff

1984
po/sr.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1893
po/sv.po

File diff suppressed because it is too large Load Diff

2701
po/ta.po

File diff suppressed because it is too large Load Diff

2603
po/tr.po

File diff suppressed because it is too large Load Diff

1947
po/ug.po

File diff suppressed because it is too large Load Diff

6209
po/uk.po

File diff suppressed because it is too large Load Diff

4122
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

File diff suppressed because it is too large Load Diff

View File

@@ -1,114 +1,71 @@
# Flag build for parallelism; see https://savannah.gnu.org/patch/?6905
.AUTOPARALLEL:
lib_LTLIBRARIES = libmutter-private.la
lib_LTLIBRARIES = libmutter.la
SUBDIRS=wm-tester tools
SUBDIRS=wm-tester tools compositor/plugins
if WITH_CLUTTER
SUBDIRS += compositor/mutter/plugins
endif
INCLUDES= \
$(MUTTER_CFLAGS) \
-I$(srcdir) \
-I$(srcdir)/core \
-I$(srcdir)/ui \
-I$(srcdir)/compositor \
-DMUTTER_LIBEXECDIR=\"$(libexecdir)\" \
-DHOST_ALIAS=\"@HOST_ALIAS@\" \
-DMUTTER_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" \
-DMUTTER_PKGDATADIR=\"$(pkgdatadir)\" \
-DMUTTER_DATADIR=\"$(datadir)\" \
-DG_LOG_DOMAIN=\"mutter\" \
-DSN_API_NOT_YET_FROZEN=1 \
-DMUTTER_MAJOR_VERSION=$(MUTTER_MAJOR_VERSION) \
-DMUTTER_MINOR_VERSION=$(MUTTER_MINOR_VERSION) \
-DMUTTER_MICRO_VERSION=$(MUTTER_MICRO_VERSION) \
-DMUTTER_PLUGIN_API_VERSION=$(MUTTER_PLUGIN_API_VERSION) \
-DMUTTER_PKGLIBDIR=\"$(pkglibdir)\" \
-DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\" \
-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\"
INCLUDES=@MUTTER_CFLAGS@ -I $(srcdir)/include -I$(srcdir)/compositor -DMUTTER_LIBEXECDIR=\"$(libexecdir)\" -DHOST_ALIAS=\"@HOST_ALIAS@\" -DMUTTER_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" -DMUTTER_PKGDATADIR=\"$(pkgdatadir)\" -DMUTTER_DATADIR=\"$(datadir)\" -DG_LOG_DOMAIN=\"mutter\" -DSN_API_NOT_YET_FROZEN=1 -DMUTTER_MAJOR_VERSION=$(MUTTER_MAJOR_VERSION) -DMUTTER_MINOR_VERSION=$(MUTTER_MINOR_VERSION) -DMUTTER_MICRO_VERSION=$(MUTTER_MICRO_VERSION) -DMUTTER_PLUGIN_API_VERSION=$(MUTTER_PLUGIN_API_VERSION) -DMUTTER_PKGLIBDIR=\"$(pkglibdir)\" -DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\"
mutter_built_sources = \
mutter-marshal.h \
mutter-marshal.c \
mutter-enum-types.h \
mutter-enum-types.c
libmutter_la_SOURCES = \
mutter_SOURCES= \
core/async-getprop.c \
core/async-getprop.h \
core/alttabhandler.c \
include/alttabhandler.h \
core/alttabhandlerdefault.c \
include/alttabhandlerdefault.h \
core/bell.c \
core/bell.h \
core/boxes.c \
core/boxes-private.h \
meta/boxes.h \
compositor/cogl-utils.c \
compositor/cogl-utils.h \
include/boxes.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 \
compositor/meta-texture-tower.h \
compositor/meta-window-actor.c \
compositor/meta-window-actor-private.h \
compositor/meta-window-group.c \
compositor/meta-window-group.h \
compositor/meta-window-shape.c \
compositor/meta-window-shape.h \
compositor/region-utils.c \
compositor/region-utils.h \
meta/compositor.h \
meta/meta-plugin.h \
meta/meta-shadow-factory.h \
meta/meta-window-actor.h \
meta/compositor-mutter.h \
core/above-tab-keycode.c \
compositor/compositor-xrender.c \
compositor/compositor-xrender.h \
include/compositor.h \
core/constraints.c \
core/constraints.h \
core/core.c \
core/delete.c \
core/display.c \
core/display-private.h \
meta/display.h \
include/display.h \
ui/draw-workspace.c \
ui/draw-workspace.h \
core/edge-resistance.c \
core/edge-resistance.h \
core/effects.c \
core/effects.h \
core/errors.c \
meta/errors.h \
include/errors.h \
core/eventqueue.c \
core/eventqueue.h \
core/frame.c \
core/frame.h \
core/frame-private.h \
include/frame.h \
ui/gradient.c \
meta/gradient.h \
ui/gradient.h \
core/group-private.h \
core/group-props.c \
core/group-props.h \
core/group.c \
meta/group.h \
include/group.h \
core/iconcache.c \
core/iconcache.h \
core/keybindings.c \
core/keybindings-private.h \
core/main.c \
core/mutter-Xatomtype.h \
include/main.h \
core/mutter-Xatomtype.h \
core/place.c \
core/place.h \
core/prefs.c \
meta/prefs.h \
include/prefs.h \
core/screen.c \
core/screen-private.h \
meta/screen.h \
meta/types.h \
include/screen.h \
include/types.h \
core/session.c \
core/session.h \
core/stack.c \
@@ -116,19 +73,19 @@ libmutter_la_SOURCES = \
core/stack-tracker.c \
core/stack-tracker.h \
core/util.c \
meta/util.h \
include/util.h \
core/window-props.c \
core/window-props.h \
core/window.c \
core/window-private.h \
meta/window.h \
include/window.h \
core/workspace.c \
core/workspace-private.h \
core/xprops.c \
core/xprops.h \
meta/common.h \
core/core.h \
ui/ui.h \
include/xprops.h \
include/common.h \
include/core.h \
include/ui.h \
inlinepixbufs.h \
ui/fixedtip.c \
ui/fixedtip.h \
@@ -139,55 +96,81 @@ libmutter_la_SOURCES = \
ui/metaaccellabel.c \
ui/metaaccellabel.h \
ui/resizepopup.c \
ui/resizepopup.h \
include/resizepopup.h \
ui/tabpopup.c \
ui/tabpopup.h \
ui/tile-preview.c \
ui/tile-preview.h \
include/tabpopup.h \
ui/theme-parser.c \
ui/theme-parser.h \
ui/theme.c \
meta/theme.h \
ui/theme-private.h \
ui/theme.h \
ui/themewidget.c \
ui/themewidget.h \
ui/ui.c \
core/all-keybindings.h \
meta/preview-widget.h \
include/all-keybindings.h
if WITH_CLUTTER
mutter_SOURCES += \
compositor/mutter/compositor-mutter.c \
compositor/mutter/mutter-shaped-texture.c \
compositor/mutter/mutter-shaped-texture.h \
compositor/mutter/mutter-plugin-manager.c \
compositor/mutter/mutter-plugin-manager.h \
compositor/mutter/tidy/tidy-texture-frame.c \
compositor/mutter/tidy/tidy-texture-frame.h \
compositor/mutter/mutter-module.c \
compositor/mutter/mutter-module.h \
compositor/mutter/mutter-plugin.c \
include/mutter-plugin.h \
include/compositor-mutter.h
endif
# by setting libmutter_private_la_CFLAGS, the files shared with
# mutter proper will be compiled with different names.
libmutter_private_la_CFLAGS =
libmutter_private_la_SOURCES= \
core/boxes.c \
include/boxes.h \
ui/gradient.c \
ui/gradient.h \
core/util.c \
include/util.h \
include/common.h \
ui/preview-widget.c \
$(mutter_built_sources)
ui/preview-widget.h \
ui/theme-parser.c \
ui/theme-parser.h \
ui/theme.c \
ui/theme.h
libmutter_la_LDFLAGS = -no-undefined
libmutter_la_LIBADD = $(MUTTER_LIBS)
libmutter_private_la_LDFLAGS = -no-undefined
libmutter_private_la_LIBADD = @MUTTER_LIBS@
libmutterincludedir = $(includedir)/mutter/mutter-private
# Headers installed for plugins; introspected information will
# be extracted into Mutter-<version>.gir
libmutterinclude_base_headers = \
meta/boxes.h \
meta/common.h \
meta/compositor-mutter.h \
meta/compositor.h \
meta/display.h \
meta/errors.h \
meta/gradient.h \
meta/group.h \
meta/keybindings.h \
meta/main.h \
meta/meta-plugin.h \
meta/meta-shadow-factory.h \
meta/meta-window-actor.h \
meta/prefs.h \
meta/screen.h \
meta/theme.h \
meta/types.h \
meta/util.h \
meta/window.h \
meta/workspace.h
include/alttabhandler.h \
include/boxes.h \
ui/gradient.h \
include/util.h \
include/common.h \
ui/preview-widget.h \
ui/theme-parser.h \
ui/theme.h \
include/prefs.h \
include/window.h \
include/workspace.h \
include/compositor.h \
include/compositor-mutter.h \
include/types.h \
include/screen.h \
include/display.h \
include/group.h \
include/keybindings.h \
include/mutter-plugin.h
# Excluded from scanning for introspection but installed
# atomnames.h: macros cause problems for scanning process
libmutterinclude_extra_headers = \
meta/preview-widget.h \
meta/atomnames.h
libmutterincludedir = $(includedir)/mutter/meta
include/atomnames.h
libmutterinclude_HEADERS = \
$(libmutterinclude_base_headers) \
@@ -198,14 +181,9 @@ mutter_theme_viewer_SOURCES= \
bin_PROGRAMS=mutter mutter-theme-viewer
mutter_SOURCES = core/mutter.c
mutter_LDADD = $(MUTTER_LIBS) libmutter.la
if HAVE_INTROSPECTION
include $(INTROSPECTION_MAKEFILE)
api_version = $(MUTTER_MAJOR_VERSION).$(MUTTER_MINOR_VERSION)
if WITH_INTROSPECTION
# These files are in package-private directories, even though they may be used
# by plugins. If you're writing a plugin, use g-ir-compiler --add-include-path
# and g-ir-compiler --includedir.
@@ -215,32 +193,44 @@ gir_DATA = Meta-$(api_version).gir
typelibdir = $(pkglibdir)
typelib_DATA = Meta-$(api_version).typelib
INTROSPECTION_GIRS = Meta-$(api_version).gir
Meta-$(api_version).gir: libmutter.la
@META_GIR@_INCLUDES = GObject-2.0 Gdk-3.0 Gtk-3.0 Clutter-1.0 xlib-2.0 xfixes-4.0
@META_GIR@_PACKAGES = clutter-1.0 gtk+-3.0
@META_GIR@_CFLAGS = $(INCLUDES)
@META_GIR@_LIBS = libmutter.la
@META_GIR@_FILES = \
mutter-enum-types.h \
$(libmutterinclude_base_headers) \
$(filter %.c,$(libmutter_la_SOURCES))
@META_GIR@_SCANNERFLAGS = --warn-all --warn-error
# We need to strip out the attribute that would point back to libmutter-introspect
# so that libgirepository looks for symbols in the executable instead
Meta-$(api_version).gir: $(G_IR_SCANNER) mutter $(libmutterinclude_HEADERS) $(mutter_SOURCES)
$(G_IR_SCANNER) \
--namespace=Meta \
--nsversion=$(api_version) \
--include=GObject-2.0 \
--include=Gdk-2.0 \
--include=Gtk-2.0 \
--include=Clutter-0.9 \
--pkg=clutter-0.9 \
--pkg=gtk+-2.0 \
--include=xfixes-4.0 \
--program=./mutter \
$(filter %.c,$(mutter_SOURCES)) \
$(libmutterinclude_base_headers) \
$(INCLUDES) \
-o $@
Meta-$(api_version).typelib: $(G_IR_COMPILER) Meta-$(api_version).gir
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. $(G_IR_COMPILER) Meta-$(api_version).gir -o $@
endif
mutter_theme_viewer_LDADD= $(MUTTER_LIBS) libmutter.la
EFENCE=
mutter_LDADD=@MUTTER_LIBS@ libmutter-private.la $(EFENCE)
mutter_LDFLAGS=-export-dynamic
testboxes_SOURCES = core/testboxes.c
testgradient_SOURCES = ui/testgradient.c
testasyncgetprop_SOURCES = core/testasyncgetprop.c
mutter_theme_viewer_LDADD= @MUTTER_LIBS@ libmutter-private.la
testboxes_SOURCES=include/util.h core/util.c include/boxes.h core/boxes.c core/testboxes.c
testgradient_SOURCES=ui/gradient.h ui/gradient.c ui/testgradient.c
testasyncgetprop_SOURCES=core/async-getprop.h core/async-getprop.c core/testasyncgetprop.c
noinst_PROGRAMS=testboxes testgradient testasyncgetprop
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la
testboxes_LDADD= @MUTTER_LIBS@ libmutter-private.la
testgradient_LDADD= @MUTTER_LIBS@ libmutter-private.la
testasyncgetprop_LDADD= @MUTTER_LIBS@ libmutter-private.la
@INTLTOOL_DESKTOP_RULE@
@@ -254,7 +244,7 @@ wmproperties_in_files=mutter-wm.desktop.in
wmproperties_files=$(wmproperties_in_files:.desktop.in=.desktop)
wmproperties_DATA = $(wmproperties_files)
schemadir = $(GCONF_SCHEMA_FILE_DIR)
schemadir = @GCONF_SCHEMA_FILE_DIR@
schema_in_files = mutter.schemas.in
schema_DATA = $(schema_in_files:.schemas.in=.schemas)
@@ -275,73 +265,21 @@ VARIABLES=stock_maximize_data $(srcdir)/stock_maximize.png \
stock_delete_data $(srcdir)/stock_delete.png
BUILT_SOURCES = inlinepixbufs.h
CLEANFILES = \
inlinepixbufs.h \
mutter.desktop \
mutter-wm.desktop \
mutter.schemas \
$(mutter_built_sources) \
$(typelib_DATA) \
$(gir_DATA)
CLEANFILES = inlinepixbufs.h mutter.desktop mutter-wm.desktop mutter.schemas
inlinepixbufs.h: $(IMAGES)
$(GDK_PIXBUF_CSOURCE) --raw --build-list $(VARIABLES) >$(srcdir)/inlinepixbufs.h
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libmutter.pc mutter-plugins.pc
pkgconfig_DATA = libmutter-private.pc mutter-plugins.pc
EXTRA_DIST=$(desktopfiles_files) \
$(wmproperties_files) \
$(IMAGES) \
$(IMAGES) $(schema_DATA) \
$(desktopfiles_in_files) \
$(wmproperties_in_files) \
$(schema_in_files) \
libmutter.pc.in \
mutter-plugins.pc.in \
mutter-enum-types.h.in \
mutter-enum-types.c.in \
mutter-marshal.list
libmutter-private.pc.in \
mutter-plugins.pc.in
BUILT_SOURCES += $(mutter_built_sources)
MUTTER_STAMP_FILES = stamp-mutter-marshal.h stamp-mutter-enum-types.h
CLEANFILES += $(MUTTER_STAMP_FILES)
mutter-marshal.h: stamp-mutter-marshal.h
@true
stamp-mutter-marshal.h: Makefile mutter-marshal.list
$(AM_V_GEN) $(GLIB_GENMARSHAL) \
--prefix=_mutter_marshal \
--header \
$(srcdir)/mutter-marshal.list > xgen-tmh && \
(cmp -s xgen-tmh mutter-marshal.h || cp -f xgen-tmh mutter-marshal.h) && \
rm -f xgen-tmh && \
echo timestamp > $(@F)
mutter-marshal.c: Makefile mutter-marshal.list
$(AM_V_GEN) (echo "#include \"mutter-marshal.h\"" ; \
$(GLIB_GENMARSHAL) \
--prefix=_mutter_marshal \
--body \
$(srcdir)/mutter-marshal.list ) > xgen-tmc && \
cp -f xgen-tmc mutter-marshal.c && \
rm -f xgen-tmc
mutter-enum-types.h: stamp-mutter-enum-types.h Makefile
@true
stamp-mutter-enum-types.h: $(libmutterinclude_base_headers) mutter-enum-types.h.in
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/mutter-enum-types.h.in \
$(libmutterinclude_base_headers) ) >> xgen-teth && \
(cmp -s xgen-teth mutter-enum-types.h || cp xgen-teth mutter-enum-types.h) && \
rm -f xgen-teth && \
echo timestamp > $(@F)
mutter-enum-types.c: stamp-mutter-enum-types.h mutter-enum-types.c.in
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/mutter-enum-types.c.in \
$(libmutterinclude_base_headers) ) >> xgen-tetc && \
cp xgen-tetc mutter-enum-types.c && \
rm -f xgen-tetc

View File

@@ -1,104 +0,0 @@
/* -*- 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

@@ -1,69 +1,90 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2008 Iain Holmes
*
* 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_COMPOSITOR_PRIVATE_H
#define META_COMPOSITOR_PRIVATE_H
#include <X11/extensions/Xfixes.h>
#include <meta/compositor.h>
#include <meta/display.h>
#include "meta-plugin-manager.h"
#include <clutter/clutter.h>
typedef struct _MetaCompScreen MetaCompScreen;
#include "compositor.h"
struct _MetaCompositor
{
MetaDisplay *display;
void (* destroy) (MetaCompositor *compositor);
Atom atom_x_root_pixmap;
Atom atom_x_set_root;
Atom atom_net_wm_window_opacity;
guint repaint_func_id;
ClutterActor *shadow_src;
MetaPlugin *modal_plugin;
gboolean show_redraw : 1;
gboolean debug : 1;
gboolean no_mipmaps : 1;
void (*manage_screen) (MetaCompositor *compositor,
MetaScreen *screen);
void (*unmanage_screen) (MetaCompositor *compositor,
MetaScreen *screen);
void (*add_window) (MetaCompositor *compositor,
MetaWindow *window);
void (*remove_window) (MetaCompositor *compositor,
MetaWindow *window);
void (*set_updates) (MetaCompositor *compositor,
MetaWindow *window,
gboolean update);
gboolean (*process_event) (MetaCompositor *compositor,
XEvent *event,
MetaWindow *window);
Pixmap (*get_window_pixmap) (MetaCompositor *compositor,
MetaWindow *window);
void (*set_active_window) (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window);
void (*map_window) (MetaCompositor *compositor,
MetaWindow *window);
void (*unmap_window) (MetaCompositor *compositor,
MetaWindow *window);
void (*minimize_window) (MetaCompositor *compositor,
MetaWindow *window,
MetaRectangle *window_rect,
MetaRectangle *icon_rect);
void (*unminimize_window) (MetaCompositor *compositor,
MetaWindow *window,
MetaRectangle *window_rect,
MetaRectangle *icon_rect);
void (*maximize_window) (MetaCompositor *compositor,
MetaWindow *window,
MetaRectangle *window_rect);
void (*unmaximize_window) (MetaCompositor *compositor,
MetaWindow *window,
MetaRectangle *window_rect);
void (*update_workspace_geometry) (MetaCompositor *compositor,
MetaWorkspace *workspace);
void (*switch_workspace) (MetaCompositor *compositor,
MetaScreen *screen,
MetaWorkspace *from,
MetaWorkspace *to,
MetaMotionDirection direction);
void (*sync_stack) (MetaCompositor *compositor,
MetaScreen *screen,
GList *stack);
void (*set_window_hidden) (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window,
gboolean hidden);
void (*sync_window_geometry) (MetaCompositor *compositor,
MetaWindow *window);
void (*sync_screen_size) (MetaCompositor *compositor,
MetaScreen *screen,
guint width,
guint height);
};
struct _MetaCompScreen
{
MetaScreen *screen;
ClutterActor *stage, *window_group, *overlay_group;
ClutterActor *background_actor;
ClutterActor *hidden_group;
GList *windows;
GHashTable *windows_by_xid;
Window output;
/* Before we create the output window */
XserverRegion pending_input_region;
gint switch_workspace_in_progress;
MetaPluginManager *plugin_mgr;
};
void meta_switch_workspace_completed (MetaScreen *screen);
void meta_set_stage_input_region (MetaScreen *screen,
XserverRegion region);
void meta_empty_stage_input_region (MetaScreen *screen);
gboolean meta_begin_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
Window grab_window,
Cursor cursor,
MetaModalOptions options,
guint32 timestamp);
void meta_end_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
guint32 timestamp);
void meta_check_end_modal (MetaScreen *screen);
#endif /* META_COMPOSITOR_PRIVATE_H */
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,10 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2008 Matthew Allum
/*
* Copyright (C) 2007 Iain Holmes
* Based on xcompmgr - (c) 2003 Keith Packard
* xfwm4 - (c) 2005-2007 Olivier Fourdan
*
*
* 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
@@ -15,30 +14,18 @@
* 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 MUTTER_H_
#define MUTTER_H_
#ifndef META_COMPOSITOR_XRENDER_H_
#define META_COMPOSITOR_XRENDER_H_
#include <clutter/clutter.h>
#include <X11/Xlib.h>
#include "types.h"
#include <meta/types.h>
#include <meta/compositor.h>
#include <meta/meta-window-actor.h>
/* Public compositor API */
ClutterActor *meta_get_stage_for_screen (MetaScreen *screen);
ClutterActor *meta_get_overlay_group_for_screen (MetaScreen *screen);
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);
MetaCompositor *meta_compositor_xrender_new (MetaDisplay *display);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,418 +0,0 @@
/* -*- 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 <meta/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);
guchar opacity = clutter_actor_get_paint_opacity (actor);
int width, height;
meta_screen_get_size (self->screen, &width, &height);
cogl_material_set_color4ub (self->material,
opacity, opacity, opacity, opacity);
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

@@ -1,58 +0,0 @@
/* -*- 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 <meta/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

@@ -1,484 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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 "compositor-private.h"
#include "meta-plugin-manager.h"
#include <meta/prefs.h>
#include <meta/errors.h>
#include <meta/workspace.h>
#include "meta-module.h"
#include "window-private.h"
#include <string.h>
#include <stdlib.h>
#include <clutter/x11/clutter-x11.h>
static GSList *plugin_types;
/*
* We have one "default plugin manager" that acts for the first screen,
* but also can be used before we open any screens, and additional
* plugin managers for each screen. (This is ugly. Probably we should
* have one plugin manager and only make the plugins per-screen.)
*/
static MetaPluginManager *default_plugin_manager;
struct MetaPluginManager
{
MetaScreen *screen;
GList /* MetaPlugin */ *plugins; /* TODO -- maybe use hash table */
};
/*
* Loads the given plugin.
*/
void
meta_plugin_manager_load (MetaPluginManager *plugin_mgr,
const gchar *plugin_name)
{
const gchar *dpath = MUTTER_PLUGIN_DIR "/";
gchar *path;
MetaModule *module;
GType plugin_type;
if (g_path_is_absolute (plugin_name))
path = g_strdup (plugin_name);
else
path = g_strconcat (dpath, plugin_name, ".so", NULL);
module = g_object_new (META_TYPE_MODULE, "path", path, NULL);
if (!module || !g_type_module_use (G_TYPE_MODULE (module)))
{
/* This is fatal under the assumption that a monitoring
* process like gnome-session will take over and handle
* our untimely exit.
*/
g_printerr ("Unable to load plugin module [%s]: %s",
path, g_module_error());
exit (1);
}
plugin_type = meta_module_get_plugin_type (module);
meta_plugin_manager_register (plugin_mgr, plugin_type);
g_type_module_unuse (G_TYPE_MODULE (module));
g_free (path);
}
/*
* Registers the given plugin type
*/
void
meta_plugin_manager_register (MetaPluginManager *plugin_mgr,
GType plugin_type)
{
MetaPlugin *plugin;
plugin_types = g_slist_prepend (plugin_types, GSIZE_TO_POINTER (plugin_type));
plugin = g_object_new (plugin_type, NULL);
plugin_mgr->plugins = g_list_prepend (plugin_mgr->plugins, plugin);
}
void
meta_plugin_manager_initialize (MetaPluginManager *plugin_mgr)
{
GList *iter;
if (!plugin_mgr->plugins)
{
/*
* If no plugins are specified, load the default plugin.
*/
meta_plugin_manager_load (plugin_mgr, "default");
}
for (iter = plugin_mgr->plugins; iter; iter = iter->next)
{
MetaPlugin *plugin = (MetaPlugin*) iter->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
g_object_set (plugin,
"screen", plugin_mgr->screen,
NULL);
if (klass->start)
klass->start (plugin);
}
}
static MetaPluginManager *
meta_plugin_manager_new (MetaScreen *screen)
{
MetaPluginManager *plugin_mgr;
plugin_mgr = g_new0 (MetaPluginManager, 1);
plugin_mgr->screen = screen;
if (screen)
g_object_set_data (G_OBJECT (screen), "meta-plugin-manager", plugin_mgr);
return plugin_mgr;
}
MetaPluginManager *
meta_plugin_manager_get_default (void)
{
if (!default_plugin_manager)
{
default_plugin_manager = meta_plugin_manager_new (NULL);
}
return default_plugin_manager;
}
MetaPluginManager *
meta_plugin_manager_get (MetaScreen *screen)
{
MetaPluginManager *plugin_mgr;
plugin_mgr = g_object_get_data (G_OBJECT (screen), "meta-plugin-manager");
if (plugin_mgr)
return plugin_mgr;
if (!default_plugin_manager)
meta_plugin_manager_get_default ();
if (!default_plugin_manager->screen)
{
/* The default plugin manager is so far unused, we can recycle it */
default_plugin_manager->screen = screen;
g_object_set_data (G_OBJECT (screen), "meta-plugin-manager", default_plugin_manager);
return default_plugin_manager;
}
else
{
GSList *iter;
GType plugin_type;
MetaPlugin *plugin;
plugin_mgr = meta_plugin_manager_new (screen);
for (iter = plugin_types; iter; iter = iter->next)
{
plugin_type = (GType)GPOINTER_TO_SIZE (iter->data);
plugin = g_object_new (plugin_type, "screen", screen, NULL);
plugin_mgr->plugins = g_list_prepend (plugin_mgr->plugins, plugin);
}
return plugin_mgr;
}
}
static void
meta_plugin_manager_kill_window_effects (MetaPluginManager *plugin_mgr,
MetaWindowActor *actor)
{
GList *l = plugin_mgr->plugins;
while (l)
{
MetaPlugin *plugin = l->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
if (!meta_plugin_disabled (plugin)
&& klass->kill_window_effects)
klass->kill_window_effects (plugin, actor);
l = l->next;
}
}
static void
meta_plugin_manager_kill_switch_workspace (MetaPluginManager *plugin_mgr)
{
GList *l = plugin_mgr->plugins;
while (l)
{
MetaPlugin *plugin = l->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
if (!meta_plugin_disabled (plugin)
&& (meta_plugin_features (plugin) & META_PLUGIN_SWITCH_WORKSPACE)
&& klass->kill_switch_workspace)
klass->kill_switch_workspace (plugin);
l = l->next;
}
}
/*
* Public method that the compositor hooks into for events that require
* no additional parameters.
*
* Returns TRUE if at least one of the plugins handled the event type (i.e.,
* if the return value is FALSE, there will be no subsequent call to the
* manager completed() callback, and the compositor must ensure that any
* appropriate post-effect cleanup is carried out.
*/
gboolean
meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
MetaWindowActor *actor,
unsigned long event)
{
GList *l = plugin_mgr->plugins;
gboolean retval = FALSE;
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return FALSE;
while (l)
{
MetaPlugin *plugin = l->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
if (!meta_plugin_disabled (plugin) &&
(meta_plugin_features (plugin) & event))
{
retval = TRUE;
switch (event)
{
case META_PLUGIN_MINIMIZE:
if (klass->minimize)
{
meta_plugin_manager_kill_window_effects (
plugin_mgr,
actor);
_meta_plugin_effect_started (plugin);
klass->minimize (plugin, actor);
}
break;
case META_PLUGIN_MAP:
if (klass->map)
{
meta_plugin_manager_kill_window_effects (
plugin_mgr,
actor);
_meta_plugin_effect_started (plugin);
klass->map (plugin, actor);
}
break;
case META_PLUGIN_DESTROY:
if (klass->destroy)
{
_meta_plugin_effect_started (plugin);
klass->destroy (plugin, actor);
}
break;
default:
g_warning ("Incorrect handler called for event %lu", event);
}
}
l = l->next;
}
return retval;
}
/*
* The public method that the compositor hooks into for maximize and unmaximize
* events.
*
* Returns TRUE if at least one of the plugins handled the event type (i.e.,
* if the return value is FALSE, there will be no subsequent call to the
* manager completed() callback, and the compositor must ensure that any
* appropriate post-effect cleanup is carried out.
*/
gboolean
meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr,
MetaWindowActor *actor,
unsigned long event,
gint target_x,
gint target_y,
gint target_width,
gint target_height)
{
GList *l = plugin_mgr->plugins;
gboolean retval = FALSE;
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return FALSE;
while (l)
{
MetaPlugin *plugin = l->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
if (!meta_plugin_disabled (plugin) &&
(meta_plugin_features (plugin) & event))
{
retval = TRUE;
switch (event)
{
case META_PLUGIN_MAXIMIZE:
if (klass->maximize)
{
meta_plugin_manager_kill_window_effects (
plugin_mgr,
actor);
_meta_plugin_effect_started (plugin);
klass->maximize (plugin, actor,
target_x, target_y,
target_width, target_height);
}
break;
case META_PLUGIN_UNMAXIMIZE:
if (klass->unmaximize)
{
meta_plugin_manager_kill_window_effects (
plugin_mgr,
actor);
_meta_plugin_effect_started (plugin);
klass->unmaximize (plugin, actor,
target_x, target_y,
target_width, target_height);
}
break;
default:
g_warning ("Incorrect handler called for event %lu", event);
}
}
l = l->next;
}
return retval;
}
/*
* The public method that the compositor hooks into for desktop switching.
*
* Returns TRUE if at least one of the plugins handled the event type (i.e.,
* if the return value is FALSE, there will be no subsequent call to the
* manager completed() callback, and the compositor must ensure that any
* appropriate post-effect cleanup is carried out.
*/
gboolean
meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr,
gint from,
gint to,
MetaMotionDirection direction)
{
GList *l = plugin_mgr->plugins;
gboolean retval = FALSE;
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return FALSE;
while (l)
{
MetaPlugin *plugin = l->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
if (!meta_plugin_disabled (plugin) &&
(meta_plugin_features (plugin) & META_PLUGIN_SWITCH_WORKSPACE))
{
if (klass->switch_workspace)
{
retval = TRUE;
meta_plugin_manager_kill_switch_workspace (plugin_mgr);
_meta_plugin_effect_started (plugin);
klass->switch_workspace (plugin, from, to, direction);
}
}
l = l->next;
}
return retval;
}
/*
* The public method that the compositor hooks into for desktop switching.
*
* Returns TRUE if at least one of the plugins handled the event type (i.e.,
* if the return value is FALSE, there will be no subsequent call to the
* manager completed() callback, and the compositor must ensure that any
* appropriate post-effect cleanup is carried out.
*/
gboolean
meta_plugin_manager_xevent_filter (MetaPluginManager *plugin_mgr,
XEvent *xev)
{
GList *l;
gboolean have_plugin_xevent_func;
if (!plugin_mgr)
return FALSE;
l = plugin_mgr->plugins;
/* We need to make sure that clutter gets certain events, like
* ConfigureNotify on the stage window. If there is a plugin that
* provides an xevent_filter function, then it's the responsibility
* of that plugin to pass events to Clutter. Otherwise, we send the
* event directly to Clutter ourselves.
*
* What happens if there are two plugins with xevent_filter functions
* is undefined; in general, multiple competing plugins are something
* we don't support well or care much about.
*
* FIXME: Really, we should just always handle sending the event to
* clutter if a plugin doesn't report the event as handled by
* returning TRUE, but it doesn't seem worth breaking compatibility
* of the plugin interface right now to achieve this; the way it is
* now works fine in practice.
*/
have_plugin_xevent_func = FALSE;
while (l)
{
MetaPlugin *plugin = l->data;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
if (klass->xevent_filter)
{
have_plugin_xevent_func = TRUE;
if (klass->xevent_filter (plugin, xev) == TRUE)
return TRUE;
}
l = l->next;
}
if (!have_plugin_xevent_func)
return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
return FALSE;
}

View File

@@ -1,82 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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_PLUGIN_MANAGER_H_
#define META_PLUGIN_MANAGER_H_
#include <meta/types.h>
#include <meta/screen.h>
#define META_PLUGIN_FROM_MANAGER_
#include <meta/meta-plugin.h>
#undef META_PLUGIN_FROM_MANAGER_
#define META_PLUGIN_MINIMIZE (1<<0)
#define META_PLUGIN_MAXIMIZE (1<<1)
#define META_PLUGIN_UNMAXIMIZE (1<<2)
#define META_PLUGIN_MAP (1<<3)
#define META_PLUGIN_DESTROY (1<<4)
#define META_PLUGIN_SWITCH_WORKSPACE (1<<5)
#define META_PLUGIN_ALL_EFFECTS (~0)
/**
* MetaPluginManager: (skip)
*
*/
typedef struct MetaPluginManager MetaPluginManager;
MetaPluginManager * meta_plugin_manager_get (MetaScreen *screen);
MetaPluginManager * meta_plugin_manager_get_default (void);
void meta_plugin_manager_load (MetaPluginManager *mgr,
const gchar *plugin_name);
void meta_plugin_manager_register (MetaPluginManager *mgr,
GType plugin_type);
void meta_plugin_manager_initialize (MetaPluginManager *mgr);
gboolean meta_plugin_manager_event_simple (MetaPluginManager *mgr,
MetaWindowActor *actor,
unsigned long event);
gboolean meta_plugin_manager_event_maximize (MetaPluginManager *mgr,
MetaWindowActor *actor,
unsigned long event,
gint target_x,
gint target_y,
gint target_width,
gint target_height);
void meta_plugin_manager_update_workspaces (MetaPluginManager *mgr);
void meta_plugin_manager_update_workspace (MetaPluginManager *mgr,
MetaWorkspace *w);
gboolean meta_plugin_manager_switch_workspace (MetaPluginManager *mgr,
gint from,
gint to,
MetaMotionDirection direction);
gboolean meta_plugin_manager_xevent_filter (MetaPluginManager *mgr,
XEvent *xev);
#endif

View File

@@ -1,566 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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 <meta/meta-plugin.h>
#include "meta-plugin-manager.h"
#include <meta/screen.h>
#include <meta/display.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/shape.h>
#include <clutter/x11/clutter-x11.h>
#include "compositor-private.h"
#include "meta-window-actor-private.h"
G_DEFINE_ABSTRACT_TYPE (MetaPlugin, meta_plugin, G_TYPE_OBJECT);
#define META_PLUGIN_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_PLUGIN, MetaPluginPrivate))
enum
{
PROP_0,
PROP_SCREEN,
PROP_FEATURES,
PROP_DISABLED,
PROP_DEBUG_MODE,
};
struct _MetaPluginPrivate
{
MetaScreen *screen;
gulong features;
gint running;
gboolean disabled : 1;
gboolean debug : 1;
};
static void
meta_plugin_set_features (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = plugin->priv;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
priv->features = 0;
/*
* Feature flags: identify events that the plugin can handle; a plugin can
* handle one or more events.
*/
if (klass->minimize)
priv->features |= META_PLUGIN_MINIMIZE;
if (klass->maximize)
priv->features |= META_PLUGIN_MAXIMIZE;
if (klass->unmaximize)
priv->features |= META_PLUGIN_UNMAXIMIZE;
if (klass->map)
priv->features |= META_PLUGIN_MAP;
if (klass->destroy)
priv->features |= META_PLUGIN_DESTROY;
if (klass->switch_workspace)
priv->features |= META_PLUGIN_SWITCH_WORKSPACE;
}
static void
meta_plugin_constructed (GObject *object)
{
meta_plugin_set_features (META_PLUGIN (object));
if (G_OBJECT_CLASS (meta_plugin_parent_class)->constructed)
G_OBJECT_CLASS (meta_plugin_parent_class)->constructed (object);
}
static void
meta_plugin_dispose (GObject *object)
{
G_OBJECT_CLASS (meta_plugin_parent_class)->dispose (object);
}
static void
meta_plugin_finalize (GObject *object)
{
G_OBJECT_CLASS (meta_plugin_parent_class)->finalize (object);
}
static void
meta_plugin_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaPluginPrivate *priv = META_PLUGIN (object)->priv;
switch (prop_id)
{
case PROP_SCREEN:
priv->screen = g_value_get_object (value);
break;
case PROP_DISABLED:
priv->disabled = g_value_get_boolean (value);
break;
case PROP_DEBUG_MODE:
priv->debug = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_plugin_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaPluginPrivate *priv = META_PLUGIN (object)->priv;
switch (prop_id)
{
case PROP_SCREEN:
g_value_set_object (value, priv->screen);
break;
case PROP_DISABLED:
g_value_set_boolean (value, priv->disabled);
break;
case PROP_DEBUG_MODE:
g_value_set_boolean (value, priv->debug);
break;
case PROP_FEATURES:
g_value_set_ulong (value, priv->features);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_plugin_class_init (MetaPluginClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->constructed = meta_plugin_constructed;
gobject_class->finalize = meta_plugin_finalize;
gobject_class->dispose = meta_plugin_dispose;
gobject_class->set_property = meta_plugin_set_property;
gobject_class->get_property = meta_plugin_get_property;
g_object_class_install_property (gobject_class,
PROP_SCREEN,
g_param_spec_object ("screen",
"MetaScreen",
"MetaScreen",
META_TYPE_SCREEN,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_FEATURES,
g_param_spec_ulong ("features",
"Features",
"Plugin Features",
0 , G_MAXULONG, 0,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_DISABLED,
g_param_spec_boolean ("disabled",
"Plugin disabled",
"Plugin disabled",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_DEBUG_MODE,
g_param_spec_boolean ("debug-mode",
"Debug Mode",
"Debug Mode",
FALSE,
G_PARAM_READABLE));
g_type_class_add_private (gobject_class, sizeof (MetaPluginPrivate));
}
static void
meta_plugin_init (MetaPlugin *self)
{
MetaPluginPrivate *priv;
self->priv = priv = META_PLUGIN_GET_PRIVATE (self);
}
gulong
meta_plugin_features (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return priv->features;
}
gboolean
meta_plugin_disabled (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return priv->disabled;
}
gboolean
meta_plugin_running (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return (priv->running > 0);
}
gboolean
meta_plugin_debug_mode (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return priv->debug;
}
const MetaPluginInfo *
meta_plugin_get_info (MetaPlugin *plugin)
{
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
if (klass && klass->plugin_info)
return klass->plugin_info (plugin);
return NULL;
}
ClutterActor *
meta_plugin_get_overlay_group (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return meta_get_overlay_group_for_screen (priv->screen);
}
ClutterActor *
meta_plugin_get_stage (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return meta_get_stage_for_screen (priv->screen);
}
ClutterActor *
meta_plugin_get_window_group (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
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
*
* Mark that an effect has started for the plugin. This is called
* internally by MetaPluginManager.
*/
void
_meta_plugin_effect_started (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
priv->running++;
}
void
meta_plugin_switch_workspace_completed (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
MetaScreen *screen = meta_plugin_get_screen (plugin);
if (priv->running-- < 0)
{
g_warning ("Error in running effect accounting, adjusting.");
priv->running = 0;
}
meta_switch_workspace_completed (screen);
}
static void
meta_plugin_window_effect_completed (MetaPlugin *plugin,
MetaWindowActor *actor,
unsigned long event)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
if (priv->running-- < 0)
{
g_warning ("Error in running effect accounting, adjusting.");
priv->running = 0;
}
if (!actor)
{
const MetaPluginInfo *info;
const gchar *name = NULL;
if (plugin && (info = meta_plugin_get_info (plugin)))
name = info->name;
g_warning ("Plugin [%s] passed NULL for actor!",
name ? name : "unknown");
}
meta_window_actor_effect_completed (actor, event);
}
void
meta_plugin_minimize_completed (MetaPlugin *plugin,
MetaWindowActor *actor)
{
meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_MINIMIZE);
}
void
meta_plugin_maximize_completed (MetaPlugin *plugin,
MetaWindowActor *actor)
{
meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_MAXIMIZE);
}
void
meta_plugin_unmaximize_completed (MetaPlugin *plugin,
MetaWindowActor *actor)
{
meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_UNMAXIMIZE);
}
void
meta_plugin_map_completed (MetaPlugin *plugin,
MetaWindowActor *actor)
{
meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_MAP);
}
void
meta_plugin_destroy_completed (MetaPlugin *plugin,
MetaWindowActor *actor)
{
meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_DESTROY);
}
void
meta_plugin_query_screen_size (MetaPlugin *plugin,
int *width,
int *height)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
meta_screen_get_size (priv->screen, width, height);
}
void
meta_plugin_set_stage_reactive (MetaPlugin *plugin,
gboolean reactive)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
if (reactive)
meta_set_stage_input_region (screen, None);
else
meta_empty_stage_input_region (screen);
}
void
meta_plugin_set_stage_input_area (MetaPlugin *plugin,
gint x, gint y, gint width, gint height)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdpy = meta_display_get_xdisplay (display);
XRectangle rect;
XserverRegion region;
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
region = XFixesCreateRegion (xdpy, &rect, 1);
meta_set_stage_input_region (screen, region);
XFixesDestroyRegion (xdpy, region);
}
void
meta_plugin_set_stage_input_region (MetaPlugin *plugin,
XserverRegion region)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
meta_set_stage_input_region (screen, region);
}
/**
* meta_plugin_get_window_actors:
* @plugin: A #MetaPlugin
*
* This function returns all of the #MetaWindowActor objects referenced by Mutter, including
* override-redirect windows. The returned list is a snapshot of Mutter's current
* stacking order, with the topmost window last.
*
* The 'restacked' signal of #MetaScreen signals when this value has changed.
*
* Returns: (transfer none) (element-type MetaWindowActor): Windows in stacking order, topmost last
*/
GList *
meta_plugin_get_window_actors (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return meta_get_window_actors (priv->screen);
}
/**
* meta_plugin_begin_modal:
* @plugin: a #MetaPlugin
* @grab_window: the X window to grab the keyboard and mouse on
* @cursor: the cursor to use for the pointer grab, or None,
* to use the normal cursor for the grab window and
* its descendants.
* @options: flags that modify the behavior of the modal grab
* @timestamp: the timestamp used for establishing grabs
*
* This function is used to grab the keyboard and mouse for the exclusive
* use of the plugin. Correct operation requires that both the keyboard
* and mouse are grabbed, or thing will break. (In particular, other
* passive X grabs in Meta can trigger but not be handled by the normal
* keybinding handling code.) However, the plugin can establish the keyboard
* and/or mouse grabs ahead of time and pass in the
* %META_MODAL_POINTER_ALREADY_GRABBED and/or %META_MODAL_KEYBOARD_ALREADY_GRABBED
* options. This facility is provided for two reasons: first to allow using
* this function to establish modality after a passive grab, and second to
* allow using obscure features of XGrabPointer() and XGrabKeyboard() without
* having to add them to this API.
*
* Return value: whether we successfully grabbed the keyboard and
* mouse and made the plugin modal.
*/
gboolean
meta_plugin_begin_modal (MetaPlugin *plugin,
Window grab_window,
Cursor cursor,
MetaModalOptions options,
guint32 timestamp)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return meta_begin_modal_for_plugin (priv->screen, plugin,
grab_window, cursor, options, timestamp);
}
/**
* meta_plugin_end_modal
* @plugin: a #MetaPlugin
* @timestamp: the time used for releasing grabs
*
* Ends the modal operation begun with meta_plugin_begin_modal(). This
* ungrabs both the mouse and keyboard even when
* %META_MODAL_POINTER_ALREADY_GRABBED or
* %META_MODAL_KEYBOARD_ALREADY_GRABBED were provided as options
* when beginnning the modal operation.
*/
void
meta_plugin_end_modal (MetaPlugin *plugin,
guint32 timestamp)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
meta_end_modal_for_plugin (priv->screen, plugin, timestamp);
}
Display *
meta_plugin_get_xdisplay (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
MetaDisplay *display = meta_screen_get_display (priv->screen);
Display *xdpy = meta_display_get_xdisplay (display);
return xdpy;
}
/**
* meta_plugin_get_screen:
* @plugin: a #MetaPlugin
*
* Gets the #MetaScreen corresponding to a plugin. Each plugin instance
* is associated with exactly one screen; if Metacity is managing
* multiple screens, multiple plugin instances will be created.
*
* Return value: (transfer none): the #MetaScreen for the plugin
*/
MetaScreen *
meta_plugin_get_screen (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return priv->screen;
}
/**
* meta_plugin_type_register:
* @plugin_type: a #MetaPlugin type
*
* Register @plugin_type as a compositor plugin type to be used.
* You must call this before calling meta_init().
*/
void
meta_plugin_type_register (GType plugin_type)
{
MetaPluginManager *plugin_manager;
plugin_manager = meta_plugin_manager_get_default ();
meta_plugin_manager_register (plugin_manager, plugin_type);
}

View File

@@ -1,67 +0,0 @@
/* -*- 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/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

@@ -1,989 +0,0 @@
/* -*- 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

@@ -1,639 +0,0 @@
/*
* shaped texture
*
* An actor to draw a texture clipped to a list of rectangles
*
* Authored By Neil Roberts <neil@linux.intel.com>
*
* Copyright (C) 2008 Intel Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <config.h>
#include "meta-shaped-texture.h"
#include "meta-texture-tower.h"
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
static void meta_shaped_texture_dispose (GObject *object);
static void meta_shaped_texture_finalize (GObject *object);
static void meta_shaped_texture_notify (GObject *object,
GParamSpec *pspec);
static void meta_shaped_texture_paint (ClutterActor *actor);
static void meta_shaped_texture_pick (ClutterActor *actor,
const ClutterColor *color);
static void meta_shaped_texture_update_area (ClutterX11TexturePixmap *texture,
int x,
int y,
int width,
int height);
static void meta_shaped_texture_dirty_mask (MetaShapedTexture *stex);
#ifdef HAVE_GLX_TEXTURE_PIXMAP
G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
CLUTTER_GLX_TYPE_TEXTURE_PIXMAP);
#else /* HAVE_GLX_TEXTURE_PIXMAP */
G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
CLUTTER_X11_TYPE_TEXTURE_PIXMAP);
#endif /* HAVE_GLX_TEXTURE_PIXMAP */
#define META_SHAPED_TEXTURE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_SHAPED_TEXTURE, \
MetaShapedTexturePrivate))
struct _MetaShapedTexturePrivate
{
MetaTextureTower *paint_tower;
CoglHandle mask_texture;
CoglHandle material;
CoglHandle material_unshaped;
cairo_region_t *clip_region;
guint mask_width, mask_height;
GArray *rectangles;
guint create_mipmaps : 1;
};
static void
meta_shaped_texture_class_init (MetaShapedTextureClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
ClutterX11TexturePixmapClass *x11_texture_class = (ClutterX11TexturePixmapClass *) klass;
gobject_class->dispose = meta_shaped_texture_dispose;
gobject_class->finalize = meta_shaped_texture_finalize;
gobject_class->notify = meta_shaped_texture_notify;
actor_class->paint = meta_shaped_texture_paint;
actor_class->pick = meta_shaped_texture_pick;
x11_texture_class->update_area = meta_shaped_texture_update_area;
g_type_class_add_private (klass, sizeof (MetaShapedTexturePrivate));
}
static void
meta_shaped_texture_init (MetaShapedTexture *self)
{
MetaShapedTexturePrivate *priv;
priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
priv->rectangles = g_array_new (FALSE, FALSE, sizeof (XRectangle));
priv->paint_tower = meta_texture_tower_new ();
priv->mask_texture = COGL_INVALID_HANDLE;
priv->create_mipmaps = TRUE;
}
static void
meta_shaped_texture_dispose (GObject *object)
{
MetaShapedTexture *self = (MetaShapedTexture *) object;
MetaShapedTexturePrivate *priv = self->priv;
if (priv->paint_tower)
meta_texture_tower_free (priv->paint_tower);
priv->paint_tower = NULL;
meta_shaped_texture_dirty_mask (self);
if (priv->material != COGL_INVALID_HANDLE)
{
cogl_handle_unref (priv->material);
priv->material = COGL_INVALID_HANDLE;
}
if (priv->material_unshaped != COGL_INVALID_HANDLE)
{
cogl_handle_unref (priv->material_unshaped);
priv->material_unshaped = COGL_INVALID_HANDLE;
}
meta_shaped_texture_set_clip_region (self, NULL);
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
}
static void
meta_shaped_texture_finalize (GObject *object)
{
MetaShapedTexture *self = (MetaShapedTexture *) object;
MetaShapedTexturePrivate *priv = self->priv;
g_array_free (priv->rectangles, TRUE);
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->finalize (object);
}
static void
meta_shaped_texture_notify (GObject *object,
GParamSpec *pspec)
{
if (G_OBJECT_CLASS (meta_shaped_texture_parent_class)->notify)
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->notify (object, pspec);
/* It seems like we could just do this out of update_area(), but unfortunately,
* clutter_glx_texture_pixmap() doesn't call through the vtable on the
* initial update_area, so we need to look for changes to the texture
* explicitly.
*/
if (strcmp (pspec->name, "cogl-texture") == 0)
{
MetaShapedTexture *stex = (MetaShapedTexture *) object;
MetaShapedTexturePrivate *priv = stex->priv;
meta_shaped_texture_clear (stex);
if (priv->create_mipmaps)
meta_texture_tower_set_base_texture (priv->paint_tower,
clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex)));
}
}
static void
meta_shaped_texture_dirty_mask (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv = stex->priv;
if (priv->mask_texture != COGL_INVALID_HANDLE)
{
GLuint mask_gl_tex;
GLenum mask_gl_target;
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;
if (priv->material != COGL_INVALID_HANDLE)
cogl_material_set_layer (priv->material, 1, COGL_INVALID_HANDLE);
}
}
static void
meta_shaped_texture_ensure_mask (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv = stex->priv;
CoglHandle paint_tex;
guint tex_width, tex_height;
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
if (paint_tex == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
/* If the mask texture we have was created for a different size then
recreate it */
if (priv->mask_texture != COGL_INVALID_HANDLE
&& (priv->mask_width != tex_width || priv->mask_height != tex_height))
meta_shaped_texture_dirty_mask (stex);
/* If we don't have a mask texture yet then create one */
if (priv->mask_texture == COGL_INVALID_HANDLE)
{
guchar *mask_data;
const XRectangle *rect;
GLenum paint_gl_target;
/* Create data for an empty image */
mask_data = g_malloc0 (tex_width * tex_height);
/* Cut out a hole for each rectangle */
for (rect = (XRectangle *) priv->rectangles->data
+ priv->rectangles->len;
rect-- > (XRectangle *) priv->rectangles->data;)
{
gint x1 = rect->x, x2 = x1 + rect->width;
gint y1 = rect->y, y2 = y1 + rect->height;
guchar *p;
/* Clip the rectangle to the size of the texture */
x1 = CLAMP (x1, 0, (gint) tex_width - 1);
x2 = CLAMP (x2, x1, (gint) tex_width);
y1 = CLAMP (y1, 0, (gint) tex_height - 1);
y2 = CLAMP (y2, y1, (gint) tex_height);
/* Fill the rectangle */
for (p = mask_data + y1 * tex_width + x1;
y1 < y2;
y1++, p += tex_width)
memset (p, 255, x2 - x1);
}
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;
glGenTextures (1, &tex);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, tex);
glPixelStorei (GL_UNPACK_ROW_LENGTH, tex_width);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0,
GL_ALPHA, tex_width, tex_height,
0, GL_ALPHA, GL_UNSIGNED_BYTE, mask_data);
priv->mask_texture
= cogl_texture_new_from_foreign (tex,
GL_TEXTURE_RECTANGLE_ARB,
tex_width, tex_height,
0, 0,
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,
COGL_PIXEL_FORMAT_ANY,
tex_width,
mask_data);
g_free (mask_data);
priv->mask_width = tex_width;
priv->mask_height = tex_height;
}
}
static void
meta_shaped_texture_paint (ClutterActor *actor)
{
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
MetaShapedTexturePrivate *priv = stex->priv;
CoglHandle paint_tex;
guint tex_width, tex_height;
ClutterActorBox alloc;
static CoglHandle material_template = COGL_INVALID_HANDLE;
static CoglHandle material_unshaped_template = COGL_INVALID_HANDLE;
CoglHandle material;
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
return;
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
clutter_actor_realize (CLUTTER_ACTOR (stex));
/* The GL EXT_texture_from_pixmap extension does allow for it to be
* used together with SGIS_generate_mipmap, however this is very
* rarely supported. Also, even when it is supported there
* are distinct performance implications from:
*
* - Updating mipmaps that we don't need
* - Having to reallocate pixmaps on the server into larger buffers
*
* So, we just unconditionally use our mipmap emulation code. If we
* wanted to use SGIS_generate_mipmap, we'd have to query COGL to
* see if it was supported (no API currently), and then if and only
* if that was the case, set the clutter texture quality to HIGH.
* Setting the texture quality to high without SGIS_generate_mipmap
* support for TFP textures will result in fallbacks to XGetImage.
*/
if (priv->create_mipmaps)
paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
else
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
if (paint_tex == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
if (tex_width == 0 || tex_height == 0) /* no contents yet */
return;
if (priv->rectangles->len < 1)
{
/* If there are no rectangles use a single-layer texture */
if (priv->material_unshaped == COGL_INVALID_HANDLE)
{
if (G_UNLIKELY (material_unshaped_template == COGL_INVALID_HANDLE))
material_unshaped_template = cogl_material_new ();
priv->material_unshaped = cogl_material_copy (material_unshaped_template);
}
material = priv->material_unshaped;
}
else
{
meta_shaped_texture_ensure_mask (stex);
if (priv->material == COGL_INVALID_HANDLE)
{
if (G_UNLIKELY (material_template == COGL_INVALID_HANDLE))
{
material_template = cogl_material_new ();
cogl_material_set_layer_combine (material_template, 1,
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
NULL);
}
priv->material = cogl_material_copy (material_template);
}
material = priv->material;
cogl_material_set_layer (material, 1, priv->mask_texture);
}
cogl_material_set_layer (material, 0, paint_tex);
{
CoglColor color;
guchar opacity = clutter_actor_get_paint_opacity (actor);
cogl_color_set_from_4ub (&color, opacity, opacity, opacity, opacity);
cogl_material_set_color (material, &color);
}
cogl_set_source (material);
clutter_actor_get_allocation_box (actor, &alloc);
if (priv->clip_region)
{
int n_rects;
int i;
/* Limit to how many separate rectangles we'll draw; beyond this just
* fall back and draw the whole thing */
# define MAX_RECTS 16
n_rects = cairo_region_num_rectangles (priv->clip_region);
if (n_rects <= MAX_RECTS)
{
float coords[8];
float x1, y1, x2, y2;
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (priv->clip_region, i, &rect);
x1 = rect.x;
y1 = rect.y;
x2 = rect.x + rect.width;
y2 = rect.y + rect.height;
coords[0] = rect.x / (alloc.x2 - alloc.x1);
coords[1] = rect.y / (alloc.y2 - alloc.y1);
coords[2] = (rect.x + rect.width) / (alloc.x2 - alloc.x1);
coords[3] = (rect.y + rect.height) / (alloc.y2 - alloc.y1);
coords[4] = coords[0];
coords[5] = coords[1];
coords[6] = coords[2];
coords[7] = coords[3];
cogl_rectangle_with_multitexture_coords (x1, y1, x2, y2,
&coords[0], 8);
}
return;
}
}
cogl_rectangle (0, 0,
alloc.x2 - alloc.x1,
alloc.y2 - alloc.y1);
}
static void
meta_shaped_texture_pick (ClutterActor *actor,
const ClutterColor *color)
{
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
MetaShapedTexturePrivate *priv = stex->priv;
/* If there are no rectangles then use the regular pick */
if (priv->rectangles->len < 1)
CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)
->pick (actor, color);
else if (clutter_actor_should_pick_paint (actor))
{
CoglHandle paint_tex;
ClutterActorBox alloc;
guint tex_width, tex_height;
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
if (paint_tex == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
if (tex_width == 0 || tex_height == 0) /* no contents yet */
return;
meta_shaped_texture_ensure_mask (stex);
cogl_set_source_color4ub (color->red, color->green, color->blue,
color->alpha);
clutter_actor_get_allocation_box (actor, &alloc);
/* Paint the mask rectangle in the given color */
cogl_set_source_texture (priv->mask_texture);
cogl_rectangle_with_texture_coords (0, 0,
alloc.x2 - alloc.x1,
alloc.y2 - alloc.y1,
0, 0, 1, 1);
}
}
static void
meta_shaped_texture_update_area (ClutterX11TexturePixmap *texture,
int x,
int y,
int width,
int height)
{
MetaShapedTexture *stex = (MetaShapedTexture *) texture;
MetaShapedTexturePrivate *priv = stex->priv;
CLUTTER_X11_TEXTURE_PIXMAP_CLASS (meta_shaped_texture_parent_class)->update_area (texture,
x, y, width, height);
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
}
ClutterActor *
meta_shaped_texture_new (void)
{
ClutterActor *self = g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
return self;
}
void
meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
gboolean create_mipmaps)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
create_mipmaps = create_mipmaps != FALSE;
if (create_mipmaps != priv->create_mipmaps)
{
CoglHandle base_texture;
priv->create_mipmaps = create_mipmaps;
base_texture = create_mipmaps ?
clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex)) : COGL_INVALID_HANDLE;
meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
}
}
/* This is a workaround for deficiencies in the hack tower:
*
* When we call clutter_x11_texture_pixmap_set_pixmap(tp, None),
* ClutterX11TexturePixmap knows that it has to get rid of the old texture, but
* clutter_texture_set_cogl_texture(texture, COGL_INVALID_HANDLE) isn't allowed, so
* it grabs the material for the texture and manually sets the texture in it. This means
* that the "cogl-texture" property isn't notified, so we don't find out about it.
*
* And if we keep the CoglX11TexturePixmap around after the X pixmap is freed, then
* we'll trigger X errors when we actually try to free it.
*
* The only correct thing to do here is to change our code to derive
* from ClutterActor and get rid of the inheritance hack tower. Once
* we want to depend on Clutter-1.4 (which has CoglTexturePixmapX11),
* that will be very easy to do.
*/
void
meta_shaped_texture_clear (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
meta_texture_tower_set_base_texture (priv->paint_tower, COGL_INVALID_HANDLE);
if (priv->material != COGL_INVALID_HANDLE)
cogl_material_set_layer (priv->material, 0, COGL_INVALID_HANDLE);
if (priv->material_unshaped != COGL_INVALID_HANDLE)
cogl_material_set_layer (priv->material_unshaped, 0, COGL_INVALID_HANDLE);
}
void
meta_shaped_texture_clear_rectangles (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
g_array_set_size (priv->rectangles, 0);
meta_shaped_texture_dirty_mask (stex);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
void
meta_shaped_texture_add_rectangle (MetaShapedTexture *stex,
const XRectangle *rect)
{
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
meta_shaped_texture_add_rectangles (stex, 1, rect);
}
void
meta_shaped_texture_add_rectangles (MetaShapedTexture *stex,
size_t num_rects,
const XRectangle *rects)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
g_array_append_vals (priv->rectangles, rects, num_rects);
meta_shaped_texture_dirty_mask (stex);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
/**
* meta_shaped_texture_set_clip_region:
* @frame: a #TidyTextureframe
* @clip_region: (transfer full): the region of the texture that
* is visible and should be painted. OWNERSHIP IS ASSUMED BY
* THE FUNCTION (for efficiency to avoid a copy.)
*
* Provides a hint to the texture about what areas of the texture
* are not completely obscured and thus need to be painted. This
* is an optimization and is not supposed to have any effect on
* the output.
*
* Typically a parent container will set the clip region before
* painting its children, and then unset it afterwards.
*/
void
meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
cairo_region_t *clip_region)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
if (priv->clip_region)
{
cairo_region_destroy (priv->clip_region);
priv->clip_region = NULL;
}
priv->clip_region = clip_region;
}

View File

@@ -1,94 +0,0 @@
/*
* shaped texture
*
* An actor to draw a texture clipped to a list of rectangles
*
* Authored By Neil Roberts <neil@linux.intel.com>
*
* Copyright (C) 2008 Intel Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef __META_SHAPED_TEXTURE_H__
#define __META_SHAPED_TEXTURE_H__
#include <config.h>
#include <clutter/clutter.h>
#ifdef HAVE_GLX_TEXTURE_PIXMAP
#include <clutter/glx/clutter-glx.h>
#else
#include <clutter/x11/clutter-x11.h>
#endif /* HAVE_GLX_TEXTURE_PIXMAP */
G_BEGIN_DECLS
#define META_TYPE_SHAPED_TEXTURE (meta_shaped_texture_get_type())
#define META_SHAPED_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),META_TYPE_SHAPED_TEXTURE, MetaShapedTexture))
#define META_SHAPED_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SHAPED_TEXTURE, MetaShapedTextureClass))
#define META_IS_SHAPED_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SHAPED_TEXTURE))
#define META_IS_SHAPED_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SHAPED_TEXTURE))
#define META_SHAPED_TEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SHAPED_TEXTURE, MetaShapedTextureClass))
typedef struct _MetaShapedTexture MetaShapedTexture;
typedef struct _MetaShapedTextureClass MetaShapedTextureClass;
typedef struct _MetaShapedTexturePrivate MetaShapedTexturePrivate;
struct _MetaShapedTextureClass
{
#ifdef HAVE_GLX_TEXTURE_PIXMAP
ClutterGLXTexturePixmapClass parent_class;
#else
ClutterX11TexturePixmapClass parent_class;
#endif
};
struct _MetaShapedTexture
{
#ifdef HAVE_GLX_TEXTURE_PIXMAP
ClutterGLXTexturePixmap parent;
#else
ClutterX11TexturePixmap parent;
#endif
MetaShapedTexturePrivate *priv;
};
GType meta_shaped_texture_get_type (void) G_GNUC_CONST;
ClutterActor *meta_shaped_texture_new (void);
void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
gboolean create_mipmaps);
void meta_shaped_texture_clear (MetaShapedTexture *stex);
void meta_shaped_texture_clear_rectangles (MetaShapedTexture *stex);
void meta_shaped_texture_add_rectangle (MetaShapedTexture *stex,
const XRectangle *rect);
void meta_shaped_texture_add_rectangles (MetaShapedTexture *stex,
size_t num_rects,
const XRectangle *rects);
/* Assumes ownership of clip_region */
void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
cairo_region_t *clip_region);
G_END_DECLS
#endif /* __META_SHAPED_TEXTURE_H__ */

View File

@@ -1,662 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* MetaTextureTower
*
* Mipmap emulation by creation of scaled down images
*
* Copyright (C) 2009 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 <math.h>
#include <string.h>
#include "meta-texture-tower.h"
#ifndef M_LOG2E
#define M_LOG2E 1.4426950408889634074
#endif
#define MAX_TEXTURE_LEVELS 12
/* If the texture format in memory doesn't match this, then Mesa
* will do the conversion, so things will still work, but it might
* be slow depending on how efficient Mesa is. These should be the
* native formats unless the display is 16bpp. If conversions
* here are a bottleneck, investigate whether we are converting when
* storing window data *into* the texture before adding extra code
* to handle multiple texture formats.
*/
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define TEXTURE_FORMAT COGL_PIXEL_FORMAT_BGRA_8888_PRE
#else
#define TEXTURE_FORMAT COGL_PIXEL_FORMAT_ARGB_8888_PRE
#endif
typedef struct
{
guint16 x1;
guint16 y1;
guint16 x2;
guint16 y2;
} Box;
struct _MetaTextureTower
{
int n_levels;
CoglHandle textures[MAX_TEXTURE_LEVELS];
CoglHandle fbos[MAX_TEXTURE_LEVELS];
Box invalid[MAX_TEXTURE_LEVELS];
};
/**
* meta_texture_tower_new:
*
* Creates a new texture tower. The base texture has to be set with
* meta_texture_tower_set_base_texture() before use.
*
* Return value: the new texture tower. Free with meta_texture_tower_free()
*/
MetaTextureTower *
meta_texture_tower_new (void)
{
MetaTextureTower *tower;
tower = g_slice_new0 (MetaTextureTower);
return tower;
}
/**
* meta_texture_tower_free:
* @tower: a #MetaTextureTower
*
* Frees a texture tower created with meta_texture_tower_new().
*/
void
meta_texture_tower_free (MetaTextureTower *tower)
{
g_return_if_fail (tower != NULL);
meta_texture_tower_set_base_texture (tower, COGL_INVALID_HANDLE);
g_slice_free (MetaTextureTower, tower);
}
#ifdef GL_TEXTURE_RECTANGLE_ARB
static gboolean
texture_is_rectangle (CoglHandle texture)
{
GLuint gl_tex;
GLenum gl_target;
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;
cogl_texture_get_gl_texture (texture, &gl_tex, &gl_target);
if (gl_target == GL_TEXTURE_RECTANGLE_ARB)
glDeleteTextures (1, &gl_tex);
#endif /* GL_TEXTURE_RECTANGLE_ARB */
cogl_handle_unref (texture);
}
/**
* meta_texture_tower_update_area:
* @tower: a MetaTextureTower
* @texture: the new texture used as a base for scaled down versions
*
* Sets the base texture that is the scaled texture that the
* scaled textures of the tower are derived from. The texture itself
* will be used as level 0 of the tower and will be referenced until
* unset or until the tower is freed.
*/
void
meta_texture_tower_set_base_texture (MetaTextureTower *tower,
CoglHandle texture)
{
int i;
g_return_if_fail (tower != NULL);
if (texture == tower->textures[0])
return;
if (tower->textures[0] != COGL_INVALID_HANDLE)
{
for (i = 1; i < tower->n_levels; i++)
{
if (tower->textures[i] != COGL_INVALID_HANDLE)
{
free_texture (tower->textures[i]);
tower->textures[i] = COGL_INVALID_HANDLE;
}
if (tower->fbos[i] != COGL_INVALID_HANDLE)
{
cogl_handle_unref (tower->fbos[i]);
tower->fbos[i] = COGL_INVALID_HANDLE;
}
}
cogl_handle_unref (tower->textures[0]);
}
tower->textures[0] = texture;
if (tower->textures[0] != COGL_INVALID_HANDLE)
{
int width, height;
cogl_handle_ref (tower->textures[0]);
width = cogl_texture_get_width (tower->textures[0]);
height = cogl_texture_get_height (tower->textures[0]);
tower->n_levels = 1 + MAX ((int)(M_LOG2E * log (width)), (int)(M_LOG2E * log (height)));
tower->n_levels = MIN(tower->n_levels, MAX_TEXTURE_LEVELS);
meta_texture_tower_update_area (tower, 0, 0, width, height);
}
else
{
tower->n_levels = 0;
}
}
/**
* meta_texture_tower_update_area:
* @tower: a MetaTextureTower
* @x: X coordinate of upper left of rectangle that changed
* @y: Y coordinate of upper left of rectangle that changed
* @width: width of rectangle that changed
* @height: height rectangle that changed
*
* Mark a region of the base texture as having changed; the next
* time a scaled down version of the base texture is retrieved,
* the appropriate area of the scaled down texture will be updated.
*/
void
meta_texture_tower_update_area (MetaTextureTower *tower,
int x,
int y,
int width,
int height)
{
int texture_width, texture_height;
Box invalid;
int i;
g_return_if_fail (tower != NULL);
texture_width = cogl_texture_get_width (tower->textures[0]);
texture_height = cogl_texture_get_height (tower->textures[0]);
invalid.x1 = x;
invalid.y1 = y;
invalid.x2 = x + width;
invalid.y2 = y + height;
for (i = 1; i < tower->n_levels; i++)
{
texture_width = MAX (1, texture_width / 2);
texture_height = MAX (1, texture_height / 2);
invalid.x1 = invalid.x1 / 2;
invalid.y1 = invalid.y1 / 2;
invalid.x2 = MIN (texture_width, (invalid.x2 + 1) / 2);
invalid.y2 = MIN (texture_height, (invalid.y2 + 1) / 2);
if (tower->invalid[i].x1 == tower->invalid[i].x2 ||
tower->invalid[i].y1 == tower->invalid[i].y2)
{
tower->invalid[i] = invalid;
}
else
{
tower->invalid[i].x1 = MIN (tower->invalid[i].x1, invalid.x1);
tower->invalid[i].y1 = MIN (tower->invalid[i].y1, invalid.y1);
tower->invalid[i].x2 = MAX (tower->invalid[i].x2, invalid.x2);
tower->invalid[i].y2 = MAX (tower->invalid[i].y2, invalid.y2);
}
}
}
/* It generally looks worse if we scale up a window texture by even a
* small amount than if we scale it down using bilinear filtering, so
* we always pick the *larger* adjacent level. */
#define LOD_BIAS (-0.49)
/* This determines the appropriate level of detail to use when drawing the
* texture, in a way that corresponds to what the GL specification does
* when mip-mapping. This is probably fancier and slower than what we need,
* but we do the computation only once each time we paint a window, and
* its easier to just use the equations from the specification than to
* come up with something simpler.
*
* If window is being painted at an angle from the viewer, then we have to
* pick a point in the texture; we use the middle of the texture (which is
* why the width/height are passed in.) This is not the normal case for
* Meta.
*/
static int
get_paint_level (int width, int height)
{
CoglMatrix projection, modelview, pm;
float v[4];
double viewport_width, viewport_height;
double u0, v0;
double xc, yc, wc;
double dxdu_, dxdv_, dydu_, dydv_;
double det_, det_sq;
double rho_sq;
double lambda;
/* See
* http://www.opengl.org/registry/doc/glspec32.core.20090803.pdf
* Section 3.8.9, p. 1.6.2. Here we have
*
* u(x,y) = x_o;
* v(x,y) = y_o;
*
* Since we are mapping 1:1 from object coordinates into pixel
* texture coordinates, the clip coordinates are:
*
* (x_c) (x_o) (u)
* (y_c) = (M_projection)(M_modelview) (y_o) = (PM) (v)
* (z_c) (z_o) (0)
* (w_c) (w_o) (1)
*/
cogl_get_projection_matrix (&projection);
cogl_get_modelview_matrix (&modelview);
cogl_matrix_multiply (&pm, &projection, &modelview);
cogl_get_viewport (v);
viewport_width = v[2];
viewport_height = v[3];
u0 = width / 2.;
v0 = height / 2.;
xc = pm.xx * u0 + pm.xy * v0 + pm.xw;
yc = pm.yx * u0 + pm.yy * v0 + pm.yw;
wc = pm.wx * u0 + pm.wy * v0 + pm.ww;
/* We'll simplify the equations below for a bit of micro-optimization.
* The commented out code is the unsimplified version.
// Partial derivates of window coordinates:
//
// x_w = 0.5 * viewport_width * x_c / w_c + viewport_center_x
// y_w = 0.5 * viewport_height * y_c / w_c + viewport_center_y
//
// with respect to u, v, using
// d(a/b)/dx = da/dx * (1/b) - a * db/dx / (b^2)
dxdu = 0.5 * viewport_width * (pm.xx - pm.wx * (xc/wc)) / wc;
dxdv = 0.5 * viewport_width * (pm.xy - pm.wy * (xc/wc)) / wc;
dydu = 0.5 * viewport_height * (pm.yx - pm.wx * (yc/wc)) / wc;
dydv = 0.5 * viewport_height * (pm.yy - pm.wy * (yc/wc)) / wc;
// Compute the inverse partials as the matrix inverse
det = dxdu * dydv - dxdv * dydu;
dudx = dydv / det;
dudy = - dxdv / det;
dvdx = - dydu / det;
dvdy = dvdu / det;
// Scale factor; maximum of the distance in texels for a change of 1 pixel
// in the X direction or 1 pixel in the Y direction
rho = MAX (sqrt (dudx * dudx + dvdx * dvdx), sqrt(dudy * dudy + dvdy * dvdy));
// Level of detail
lambda = log2 (rho) + LOD_BIAS;
*/
/* dxdu * wc, etc */
dxdu_ = 0.5 * viewport_width * (pm.xx - pm.wx * (xc/wc));
dxdv_ = 0.5 * viewport_width * (pm.xy - pm.wy * (xc/wc));
dydu_ = 0.5 * viewport_height * (pm.yx - pm.wx * (yc/wc));
dydv_ = 0.5 * viewport_height * (pm.yy - pm.wy * (yc/wc));
/* det * wc^2 */
det_ = dxdu_ * dydv_ - dxdv_ * dydu_;
det_sq = det_ * det_;
if (det_sq == 0.0)
return -1;
/* (rho * det * wc)^2 */
rho_sq = MAX (dydv_ * dydv_ + dydu_ * dydu_, dxdv_ * dxdv_ + dxdu_ * dxdu_);
lambda = 0.5 * M_LOG2E * log (rho_sq * wc * wc / det_sq) + LOD_BIAS;
#if 0
g_print ("%g %g %g\n", 0.5 * viewport_width * pm.xx / pm.ww, 0.5 * viewport_height * pm.yy / pm.ww, lambda);
#endif
if (lambda <= 0.)
return 0;
else
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,
int level,
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]))
{
GLuint tex = 0;
glGenTextures (1, &tex);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, tex);
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0,
GL_RGBA, width,height,
#if TEXTURE_FORMAT == COGL_PIXEL_FORMAT_BGRA_8888_PRE
0, GL_BGRA, GL_UNSIGNED_BYTE,
#else /* assume big endian */
0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
#endif
NULL);
tower->textures[level] = cogl_texture_new_from_foreign (tex, GL_TEXTURE_RECTANGLE_ARB,
width, height,
0, 0,
TEXTURE_FORMAT);
}
else
#endif /* GL_TEXTURE_RECTANGLE_ARB */
{
tower->textures[level] = cogl_texture_new_with_size (width, height,
COGL_TEXTURE_NO_AUTO_MIPMAP,
TEXTURE_FORMAT);
}
tower->invalid[level].x1 = 0;
tower->invalid[level].y1 = 0;
tower->invalid[level].x2 = width;
tower->invalid[level].y2 = height;
}
static gboolean
texture_tower_revalidate_fbo (MetaTextureTower *tower,
int level)
{
CoglHandle source_texture = tower->textures[level - 1];
int source_texture_width = cogl_texture_get_width (source_texture);
int source_texture_height = cogl_texture_get_height (source_texture);
CoglHandle dest_texture = tower->textures[level];
int dest_texture_width = cogl_texture_get_width (dest_texture);
int dest_texture_height = cogl_texture_get_height (dest_texture);
Box *invalid = &tower->invalid[level];
CoglMatrix modelview;
if (tower->fbos[level] == COGL_INVALID_HANDLE)
{
/* Work around http://bugzilla.openedhand.com/show_bug.cgi?id=2110 */
cogl_flush();
tower->fbos[level] = cogl_offscreen_new_to_texture (dest_texture);
}
if (tower->fbos[level] == COGL_INVALID_HANDLE)
return FALSE;
cogl_push_framebuffer (tower->fbos[level]);
cogl_ortho (0, dest_texture_width, dest_texture_height, 0, -1., 1.);
cogl_matrix_init_identity (&modelview);
cogl_set_modelview_matrix (&modelview);
cogl_set_source_texture (tower->textures[level - 1]);
cogl_rectangle_with_texture_coords (invalid->x1, invalid->y1,
invalid->x2, invalid->y2,
(2. * invalid->x1) / source_texture_width,
(2. * invalid->y1) / source_texture_height,
(2. * invalid->x2) / source_texture_width,
(2. * invalid->y2) / source_texture_height);
cogl_pop_framebuffer ();
return TRUE;
}
static void
fill_copy (guchar *buf,
const guchar *source,
int width)
{
memcpy (buf, source, width * 4);
}
static void
fill_scale_down (guchar *buf,
const guchar *source,
int width)
{
while (width > 1)
{
buf[0] = (source[0] + source[4]) / 2;
buf[1] = (source[1] + source[5]) / 2;
buf[2] = (source[2] + source[6]) / 2;
buf[3] = (source[3] + source[7]) / 2;
buf += 4;
source += 8;
width -= 2;
}
if (width > 0)
{
buf[0] = source[0] / 2;
buf[1] = source[1] / 2;
buf[2] = source[2] / 2;
buf[3] = source[3] / 2;
}
}
static void
texture_tower_revalidate_client (MetaTextureTower *tower,
int level)
{
CoglHandle source_texture = tower->textures[level - 1];
int source_texture_width = cogl_texture_get_width (source_texture);
int source_texture_height = cogl_texture_get_height (source_texture);
guint source_rowstride;
guchar *source_data;
CoglHandle dest_texture = tower->textures[level];
int dest_texture_width = cogl_texture_get_width (dest_texture);
int dest_texture_height = cogl_texture_get_height (dest_texture);
int dest_x = tower->invalid[level].x1;
int dest_y = tower->invalid[level].y1;
int dest_width = tower->invalid[level].x2 - tower->invalid[level].x1;
int dest_height = tower->invalid[level].y2 - tower->invalid[level].y1;
guchar *dest_data;
guchar *source_tmp1 = NULL, *source_tmp2 = NULL;
int i, j;
source_rowstride = source_texture_width * 4;
source_data = g_malloc (source_texture_height * source_rowstride);
cogl_texture_get_data (source_texture, TEXTURE_FORMAT, source_rowstride,
source_data);
dest_data = g_malloc (dest_height * dest_width * 4);
if (dest_texture_height < source_texture_height)
{
source_tmp1 = g_malloc (dest_width * 4);
source_tmp2 = g_malloc (dest_width * 4);
}
for (i = 0; i < dest_height; i++)
{
guchar *dest_row = dest_data + i * dest_width * 4;
if (dest_texture_height < source_texture_height)
{
guchar *source1, *source2;
guchar *dest;
if (dest_texture_width < source_texture_width)
{
fill_scale_down (source_tmp1,
source_data + ((i + dest_y) * 2) * source_rowstride + dest_x * 2 * 4,
dest_width * 2);
fill_scale_down (source_tmp2,
source_data + ((i + dest_y) * 2 + 1) * source_rowstride + dest_x * 2 * 4,
dest_width * 2);
}
else
{
fill_copy (source_tmp1,
source_data + ((i + dest_y) * 2) * source_rowstride + dest_x * 4,
dest_width);
fill_copy (source_tmp2,
source_data + ((i + dest_y) * 2 + 1) * source_rowstride + dest_x * 4,
dest_width);
}
source1 = source_tmp1;
source2 = source_tmp2;
dest = dest_row;
for (j = 0; j < dest_width * 4; j++)
*(dest++) = (*(source1++) + *(source2++)) / 2;
}
else
{
if (dest_texture_width < source_texture_width)
fill_scale_down (dest_row,
source_data + (i + dest_y) * source_rowstride + dest_x * 2 * 4,
dest_width * 2);
else
fill_copy (dest_row,
source_data + (i + dest_y) * source_rowstride,
dest_width);
}
}
cogl_texture_set_region (dest_texture,
0, 0,
dest_x, dest_y,
dest_width, dest_height,
dest_width, dest_height,
TEXTURE_FORMAT,
4 * dest_width,
dest_data);
if (dest_height < source_texture_height)
{
g_free (source_tmp1);
g_free (source_tmp2);
}
g_free (source_data);
g_free (dest_data);
}
static void
texture_tower_revalidate (MetaTextureTower *tower,
int level)
{
if (!texture_tower_revalidate_fbo (tower, level))
texture_tower_revalidate_client (tower, level);
}
/**
* meta_texture_tower_get_paint_texture:
* @tower: a MetaTextureTower
*
* Gets the texture from the tower that best matches the current
* rendering scale. (On the assumption here the texture is going to
* be rendered with vertex coordinates that correspond to its
* size in pixels, so a 200x200 texture will be rendered on the
* rectangle (0, 0, 200, 200).
*
* Return value: the COGL texture handle to use for painting, or
* %COGL_INVALID_HANDLE if no base texture has yet been set.
*/
CoglHandle
meta_texture_tower_get_paint_texture (MetaTextureTower *tower)
{
int texture_width, texture_height;
int level;
g_return_val_if_fail (tower != NULL, COGL_INVALID_HANDLE);
if (tower->textures[0] == COGL_INVALID_HANDLE)
return COGL_INVALID_HANDLE;
texture_width = cogl_texture_get_width (tower->textures[0]);
texture_height = cogl_texture_get_height (tower->textures[0]);
level = get_paint_level(texture_width, texture_height);
if (level < 0) /* singular paint matrix, scaled to nothing */
return COGL_INVALID_HANDLE;
level = MIN (level, tower->n_levels - 1);
if (tower->textures[level] == COGL_INVALID_HANDLE ||
(tower->invalid[level].x2 != tower->invalid[level].x1 &&
tower->invalid[level].y2 != tower->invalid[level].y1))
{
int i;
for (i = 1; i <= level; i++)
{
/* Use "floor" convention here to be consistent with the NPOT texture extension */
texture_width = MAX (1, texture_width / 2);
texture_height = MAX (1, texture_height / 2);
if (tower->textures[i] == COGL_INVALID_HANDLE)
texture_tower_create_texture (tower, i, texture_width, texture_height);
}
for (i = 1; i <= level; i++)
{
if (tower->invalid[level].x2 != tower->invalid[level].x1 &&
tower->invalid[level].y2 != tower->invalid[level].y1)
texture_tower_revalidate (tower, i);
}
}
return tower->textures[level];
}

View File

@@ -1,69 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* MetaTextureTower
*
* Mipmap emulation by creation of scaled down images
*
* Copyright (C) 2009 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_TEXTURE_TOWER_H__
#define __META_TEXTURE_TOWER_H__
#include <clutter/clutter.h>
G_BEGIN_DECLS
/**
* SECTION:MetaTextureTower
* @short_description: mipmap emulation by creation of scaled down images
*
* A #MetaTextureTower is used to get good looking scaled down images when
* we can't use the GL drivers mipmap support. There are two separate reasons
*
* - Some cards (including radeon cards <= r5xx) only support
* TEXTURE_RECTANGLE_ARB and not NPOT textures. Rectangular textures
* are defined not to support mipmapping.
* - Even when NPOT textures are available, the combination of NPOT
* textures, texture_from_pixmap, and mipmapping doesn't typically
* work, since the X server doesn't allocate pixmaps in the right
* layout for mipmapping.
*
* So, what we do is create the "mipmap" levels ourselves by successive
* power-of-two scaledowns, and when rendering pick the single texture
* that best matches the scale we are rendering at. (Since we aren't
* typically using perspective transforms, we'll frequently have a single
* scale for the entire texture.)
*/
typedef struct _MetaTextureTower MetaTextureTower;
MetaTextureTower *meta_texture_tower_new (void);
void meta_texture_tower_free (MetaTextureTower *tower);
void meta_texture_tower_set_base_texture (MetaTextureTower *tower,
CoglHandle texture);
void meta_texture_tower_update_area (MetaTextureTower *tower,
int x,
int y,
int width,
int height);
CoglHandle meta_texture_tower_get_paint_texture (MetaTextureTower *tower);
G_BEGIN_DECLS
#endif /* __META_TEXTURE_TOWER_H__ */

View File

@@ -1,53 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef META_WINDOW_ACTOR_PRIVATE_H
#define META_WINDOW_ACTOR_PRIVATE_H
#include <config.h>
#include <X11/extensions/Xdamage.h>
#include <meta/compositor-mutter.h>
MetaWindowActor *meta_window_actor_new (MetaWindow *window);
void meta_window_actor_destroy (MetaWindowActor *self);
void meta_window_actor_show (MetaWindowActor *self,
MetaCompEffect effect);
void meta_window_actor_hide (MetaWindowActor *self,
MetaCompEffect effect);
void meta_window_actor_maximize (MetaWindowActor *self,
MetaRectangle *old_rect,
MetaRectangle *new_rect);
void meta_window_actor_unmaximize (MetaWindowActor *self,
MetaRectangle *old_rect,
MetaRectangle *new_rect);
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);
void meta_window_actor_update_shape (MetaWindowActor *self,
gboolean shaped);
void meta_window_actor_update_opacity (MetaWindowActor *self);
void meta_window_actor_mapped (MetaWindowActor *self);
void meta_window_actor_unmapped (MetaWindowActor *self);
cairo_region_t *meta_window_actor_get_obscured_region (MetaWindowActor *self);
void meta_window_actor_set_visible_region (MetaWindowActor *self,
cairo_region_t *visible_region);
void meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
cairo_region_t *beneath_region);
void meta_window_actor_reset_visible_regions (MetaWindowActor *self);
void meta_window_actor_effect_completed (MetaWindowActor *actor,
gulong event);
#endif /* META_WINDOW_ACTOR_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,237 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include <config.h>
#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
{
ClutterGroupClass parent_class;
};
struct _MetaWindowGroup
{
ClutterGroup parent;
MetaScreen *screen;
};
G_DEFINE_TYPE (MetaWindowGroup, meta_window_group, CLUTTER_TYPE_GROUP);
/* We want to find out if the window is "close enough" to
* 1:1 transform. We do that by converting the transformed coordinates
* to 24.8 fixed-point before checking if they look right.
*/
static inline int
round_to_fixed (float x)
{
return roundf (x * 256);
}
/* We can only (easily) apply our logic for figuring out what a window
* obscures if is not transformed. This function does that check and
* as a side effect gets the position of the upper-left corner of the
* actors.
*
* (We actually could handle scaled and non-integrally positioned actors
* too as long as they weren't shaped - no filtering is done at the
* edges so a rectangle stays a rectangle. But the gain from that is
* small, especally since most of our windows are shaped. The simple
* case we handle here is the case that matters when the user is just
* using the desktop normally.)
*
* If we assume that the window group is untransformed (it better not
* be!) then we could also make this determination by checking directly
* if the actor itself is rotated, scaled, or at a non-integral position.
* However, the criterion for "close enough" in that case get trickier,
* since, for example, the allowed rotation depends on the size of
* actor. The approach we take here is to just require everything
* to be within 1/256th of a pixel.
*/
static gboolean
actor_is_untransformed (ClutterActor *actor,
int *x_origin,
int *y_origin)
{
gfloat widthf, heightf;
int width, height;
ClutterVertex verts[4];
int v0x, v0y, v1x, v1y, v2x, v2y, v3x, v3y;
int x, y;
clutter_actor_get_size (actor, &widthf, &heightf);
width = round_to_fixed (widthf); height = round_to_fixed (heightf);
clutter_actor_get_abs_allocation_vertices (actor, verts);
v0x = round_to_fixed (verts[0].x); v0y = round_to_fixed (verts[0].y);
v1x = round_to_fixed (verts[1].x); v1y = round_to_fixed (verts[1].y);
v2x = round_to_fixed (verts[2].x); v2y = round_to_fixed (verts[2].y);
v3x = round_to_fixed (verts[3].x); v3y = round_to_fixed (verts[3].y);
/* Using shifting for converting fixed => int, gets things right for
* negative values. / 256. wouldn't do the same
*/
x = v0x >> 8;
y = v0y >> 8;
/* At integral coordinates? */
if (x * 256 != v0x || y * 256 != v0y)
return FALSE;
/* Not scaled? */
if (v1x - v0x != width || v2y - v0y != height)
return FALSE;
/* Not rotated/skewed? */
if (v0x != v2x || v0y != v1y ||
v3x != v1x || v3y != v2y)
return FALSE;
*x_origin = x;
*y_origin = y;
return TRUE;
}
static void
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),
* and subtract the opaque area of each window out of the visible
* region that we pass to the windows below.
*/
children = clutter_container_get_children (CLUTTER_CONTAINER (actor));
children = g_list_reverse (children);
/* Start off with the full screen area (for a multihead setup, we
* might want to use a more accurate union of the monitors to avoid
* painting in holes from mismatched monitor sizes. That's just an
* optimization, however.)
*/
meta_screen_get_size (window_group->screen, &screen_rect.width, &screen_rect.height);
/* 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)
{
if (!CLUTTER_ACTOR_IS_VISIBLE (l->data))
continue;
if (META_IS_WINDOW_ACTOR (l->data))
{
MetaWindowActor *window_actor = l->data;
gboolean 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);
CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
/* Now that we are done painting, unset the visible regions (they will
* mess up painting clones of our actors)
*/
for (l = children; l; l = l->next)
{
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);
}
static void
meta_window_group_class_init (MetaWindowGroupClass *klass)
{
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
actor_class->paint = meta_window_group_paint;
}
static void
meta_window_group_init (MetaWindowGroup *window_group)
{
}
ClutterActor *
meta_window_group_new (MetaScreen *screen)
{
MetaWindowGroup *window_group;
window_group = g_object_new (META_TYPE_WINDOW_GROUP, NULL);
window_group->screen = screen;
return CLUTTER_ACTOR (window_group);
}

View File

@@ -1,52 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef META_WINDOW_GROUP_H
#define META_WINDOW_GROUP_H
#include <clutter/clutter.h>
#include <meta/screen.h>
/**
* MetaWindowGroup:
*
* This class is a subclass of ClutterGroup with special handling for
* MetaWindowActor when painting the group. When we are painting a stack
* of 5-10 maximized windows, the standard bottom-to-top method of
* drawing every actor results in a tremendous amount of overdraw
* and can easily max out the available memory bandwidth on a low-end
* graphics chipset. It's even worse if window textures are being accessed
* over the AGP bus.
*
* The basic technique applied here is to do a pre-pass before painting
* where we walk window from top to bottom and compute the visible area
* at each step by subtracting out the windows above it. The visible
* area is passed to MetaWindowActor which uses it to clip the portion of
* the window which drawn and avoid redrawing the shadow if it is completely
* obscured.
*
* A caveat is that this is ineffective if applications are using ARGB
* visuals, since we have no way of knowing whether a window obscures
* the windows behind it or not. Alternate approaches using the depth
* or stencil buffer rather than client side regions might be able to
* handle alpha windows, but the combination of glAlphaFunc and stenciling
* tends not to be efficient except on newer cards. (And on newer cards
* we have lots of memory and bandwidth.)
*/
#define META_TYPE_WINDOW_GROUP (meta_window_group_get_type ())
#define META_WINDOW_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW_GROUP, MetaWindowGroup))
#define META_WINDOW_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW_GROUP, MetaWindowGroupClass))
#define META_IS_WINDOW_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WINDOW_GROUP))
#define META_IS_WINDOW_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WINDOW_GROUP))
#define META_WINDOW_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WINDOW_GROUP, MetaWindowGroupClass))
typedef struct _MetaWindowGroup MetaWindowGroup;
typedef struct _MetaWindowGroupClass MetaWindowGroupClass;
typedef struct _MetaWindowGroupPrivate MetaWindowGroupPrivate;
GType meta_window_group_get_type (void);
ClutterActor *meta_window_group_new (MetaScreen *screen);
#endif /* META_WINDOW_GROUP_H */

View File

@@ -1,254 +0,0 @@
/* -*- 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

@@ -1,60 +0,0 @@
/* -*- 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 __*/

File diff suppressed because it is too large Load Diff

View File

@@ -21,8 +21,8 @@
* 02111-1307, USA.
*/
#include <meta/meta-plugin.h>
#include "meta-module.h"
#include "mutter-plugin.h"
#include "mutter-module.h"
#include <gmodule.h>
@@ -32,23 +32,23 @@ enum
PROP_PATH,
};
struct _MetaModulePrivate
struct _MutterModulePrivate
{
GModule *lib;
gchar *path;
GType plugin_type;
};
#define META_MODULE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_MODULE, MetaModulePrivate))
#define MUTTER_MODULE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_MODULE, MutterModulePrivate))
G_DEFINE_TYPE (MetaModule, meta_module, G_TYPE_TYPE_MODULE);
G_DEFINE_TYPE (MutterModule, mutter_module, G_TYPE_TYPE_MODULE);
static gboolean
meta_module_load (GTypeModule *gmodule)
mutter_module_load (GTypeModule *gmodule)
{
MetaModulePrivate *priv = META_MODULE (gmodule)->priv;
MetaPluginVersion *info = NULL;
MutterModulePrivate *priv = MUTTER_MODULE (gmodule)->priv;
MutterPluginVersion *info = NULL;
GType (*register_type) (GTypeModule *) = NULL;
if (priv->lib && priv->plugin_type)
@@ -64,9 +64,9 @@ meta_module_load (GTypeModule *gmodule)
return FALSE;
}
if (g_module_symbol (priv->lib, "meta_plugin_version",
if (g_module_symbol (priv->lib, "mutter_plugin_version",
(gpointer *)(void *)&info) &&
g_module_symbol (priv->lib, "meta_plugin_register_type",
g_module_symbol (priv->lib, "mutter_plugin_register_type",
(gpointer *)(void *)&register_type) &&
info && register_type)
{
@@ -97,9 +97,9 @@ meta_module_load (GTypeModule *gmodule)
}
static void
meta_module_unload (GTypeModule *gmodule)
mutter_module_unload (GTypeModule *gmodule)
{
MetaModulePrivate *priv = META_MODULE (gmodule)->priv;
MutterModulePrivate *priv = MUTTER_MODULE (gmodule)->priv;
g_module_close (priv->lib);
@@ -108,29 +108,29 @@ meta_module_unload (GTypeModule *gmodule)
}
static void
meta_module_dispose (GObject *object)
mutter_module_dispose (GObject *object)
{
G_OBJECT_CLASS (meta_module_parent_class)->dispose (object);
G_OBJECT_CLASS (mutter_module_parent_class)->dispose (object);
}
static void
meta_module_finalize (GObject *object)
mutter_module_finalize (GObject *object)
{
MetaModulePrivate *priv = META_MODULE (object)->priv;
MutterModulePrivate *priv = MUTTER_MODULE (object)->priv;
g_free (priv->path);
priv->path = NULL;
G_OBJECT_CLASS (meta_module_parent_class)->finalize (object);
G_OBJECT_CLASS (mutter_module_parent_class)->finalize (object);
}
static void
meta_module_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
mutter_module_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaModulePrivate *priv = META_MODULE (object)->priv;
MutterModulePrivate *priv = MUTTER_MODULE (object)->priv;
switch (prop_id)
{
@@ -145,12 +145,12 @@ meta_module_set_property (GObject *object,
}
static void
meta_module_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
mutter_module_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaModulePrivate *priv = META_MODULE (object)->priv;
MutterModulePrivate *priv = MUTTER_MODULE (object)->priv;
switch (prop_id)
{
@@ -164,18 +164,18 @@ meta_module_get_property (GObject *object,
}
static void
meta_module_class_init (MetaModuleClass *klass)
mutter_module_class_init (MutterModuleClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GTypeModuleClass *gmodule_class = G_TYPE_MODULE_CLASS (klass);
gobject_class->finalize = meta_module_finalize;
gobject_class->dispose = meta_module_dispose;
gobject_class->set_property = meta_module_set_property;
gobject_class->get_property = meta_module_get_property;
gobject_class->finalize = mutter_module_finalize;
gobject_class->dispose = mutter_module_dispose;
gobject_class->set_property = mutter_module_set_property;
gobject_class->get_property = mutter_module_get_property;
gmodule_class->load = meta_module_load;
gmodule_class->unload = meta_module_unload;
gmodule_class->load = mutter_module_load;
gmodule_class->unload = mutter_module_unload;
g_object_class_install_property (gobject_class,
PROP_PATH,
@@ -186,22 +186,22 @@ meta_module_class_init (MetaModuleClass *klass)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_type_class_add_private (gobject_class, sizeof (MetaModulePrivate));
g_type_class_add_private (gobject_class, sizeof (MutterModulePrivate));
}
static void
meta_module_init (MetaModule *self)
mutter_module_init (MutterModule *self)
{
MetaModulePrivate *priv;
MutterModulePrivate *priv;
self->priv = priv = META_MODULE_GET_PRIVATE (self);
self->priv = priv = MUTTER_MODULE_GET_PRIVATE (self);
}
GType
meta_module_get_plugin_type (MetaModule *module)
mutter_module_get_plugin_type (MutterModule *module)
{
MetaModulePrivate *priv = META_MODULE (module)->priv;
MutterModulePrivate *priv = MUTTER_MODULE (module)->priv;
return priv->plugin_type;
}

View File

@@ -21,37 +21,37 @@
* 02111-1307, USA.
*/
#ifndef META_MODULE_H_
#define META_MODULE_H_
#ifndef MUTTER_MODULE_H_
#define MUTTER_MODULE_H_
#include <glib-object.h>
#define META_TYPE_MODULE (meta_module_get_type ())
#define META_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MODULE, MetaModule))
#define META_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MODULE, MetaModuleClass))
#define META_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_MODULE_TYPE))
#define META_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MODULE))
#define META_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MODULE, MetaModuleClass))
#define MUTTER_TYPE_MODULE (mutter_module_get_type ())
#define MUTTER_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUTTER_TYPE_MODULE, MutterModule))
#define MUTTER_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MUTTER_TYPE_MODULE, MutterModuleClass))
#define MUTTER_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUTTER_MODULE_TYPE))
#define MUTTER_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MUTTER_TYPE_MODULE))
#define MUTTER_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MUTTER_TYPE_MODULE, MutterModuleClass))
typedef struct _MetaModule MetaModule;
typedef struct _MetaModuleClass MetaModuleClass;
typedef struct _MetaModulePrivate MetaModulePrivate;
typedef struct _MutterModule MutterModule;
typedef struct _MutterModuleClass MutterModuleClass;
typedef struct _MutterModulePrivate MutterModulePrivate;
struct _MetaModule
struct _MutterModule
{
GTypeModule parent;
MetaModulePrivate *priv;
MutterModulePrivate *priv;
};
struct _MetaModuleClass
struct _MutterModuleClass
{
GTypeModuleClass parent_class;
};
GType meta_module_get_type (void);
GType mutter_module_get_type (void);
GType meta_module_get_plugin_type (MetaModule *module);
GType mutter_module_get_plugin_type (MutterModule *module);
#endif

View File

@@ -0,0 +1,609 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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 "mutter-plugin-manager.h"
#include "prefs.h"
#include "errors.h"
#include "workspace.h"
#include "mutter-module.h"
#include <string.h>
/*
* There is only one instace of each module per the process.
*/
static GHashTable *plugin_modules = NULL;
static gboolean mutter_plugin_manager_reload (MutterPluginManager *plugin_mgr);
struct MutterPluginManager
{
MetaScreen *screen;
GList /* MutterPluginPending */ *pending_plugin_modules; /* Plugins not yet fully loaded */
GList /* MutterPlugin */ *plugins; /* TODO -- maybe use hash table */
GList *unload; /* Plugins that are disabled and pending unload */
guint idle_unload_id;
};
typedef struct MutterPluginPending
{
MutterModule *module;
char *path;
char *params;
} MutterPluginPending;
/*
* Checks that the plugin is compatible with the WM and sets up the plugin
* struct.
*/
static MutterPlugin *
mutter_plugin_load (MutterPluginManager *mgr,
MutterModule *module,
const gchar *params)
{
MutterPlugin *plugin = NULL;
GType plugin_type = mutter_module_get_plugin_type (module);
if (!plugin_type)
{
g_warning ("Plugin type not registered !!!");
return NULL;
}
plugin = g_object_new (plugin_type,
"screen", mgr->screen,
"params", params,
NULL);
return plugin;
}
/*
* Attempst to unload a plugin; returns FALSE if plugin cannot be unloaded at
* present (e.g., and effect is in progress) and should be scheduled for
* removal later.
*/
static gboolean
mutter_plugin_unload (MutterPlugin *plugin)
{
if (mutter_plugin_running (plugin))
{
g_object_set (plugin, "disabled", TRUE, NULL);
return FALSE;
}
g_object_unref (plugin);
return TRUE;
}
/*
* Iddle callback to remove plugins that could not be removed directly and are
* pending for removal.
*/
static gboolean
mutter_plugin_manager_idle_unload (MutterPluginManager *plugin_mgr)
{
GList *l = plugin_mgr->unload;
gboolean dont_remove = TRUE;
while (l)
{
MutterPlugin *plugin = l->data;
if (mutter_plugin_unload (plugin))
{
/* Remove from list */
GList *p = l->prev;
GList *n = l->next;
if (!p)
plugin_mgr->unload = n;
else
p->next = n;
if (n)
n->prev = p;
g_list_free_1 (l);
l = n;
}
else
l = l->next;
}
if (!plugin_mgr->unload)
{
/* If no more unloads are pending, remove the handler as well */
dont_remove = FALSE;
plugin_mgr->idle_unload_id = 0;
}
return dont_remove;
}
/*
* Unloads all plugins
*/
static void
mutter_plugin_manager_unload (MutterPluginManager *plugin_mgr)
{
GList *plugins = plugin_mgr->plugins;
while (plugins)
{
MutterPlugin *plugin = plugins->data;
/* If the plugin could not be removed, move it to the unload list */
if (!mutter_plugin_unload (plugin))
{
plugin_mgr->unload = g_list_prepend (plugin_mgr->unload, plugin);
if (!plugin_mgr->idle_unload_id)
{
plugin_mgr->idle_unload_id = g_idle_add ((GSourceFunc)
mutter_plugin_manager_idle_unload,
plugin_mgr);
}
}
plugins = plugins->next;
}
g_list_free (plugin_mgr->plugins);
plugin_mgr->plugins = NULL;
}
static void
prefs_changed_callback (MetaPreference pref,
void *data)
{
MutterPluginManager *plugin_mgr = data;
if (pref == META_PREF_CLUTTER_PLUGINS)
{
mutter_plugin_manager_reload (plugin_mgr);
}
}
static MutterModule *
mutter_plugin_manager_get_module (const gchar *path)
{
MutterModule *module = g_hash_table_lookup (plugin_modules, path);
if (!module &&
(module = g_object_new (MUTTER_TYPE_MODULE, "path", path, NULL)))
{
g_hash_table_insert (plugin_modules, g_strdup (path), module);
}
return module;
}
/*
* Loads all plugins listed in gconf registry.
*/
gboolean
mutter_plugin_manager_load (MutterPluginManager *plugin_mgr)
{
const gchar *dpath = MUTTER_PLUGIN_DIR "/";
GSList *plugins, *fallback = NULL;
plugins = meta_prefs_get_clutter_plugins ();
if (!plugins)
{
/*
* If no plugins are specified, try to load the default plugin.
*/
fallback = g_slist_append (fallback, "default");
plugins = fallback;
}
while (plugins)
{
gchar *plugin_string;
gchar *params;
plugin_string = g_strdup (plugins->data);
if (plugin_string)
{
MutterModule *module;
gchar *path;
params = strchr (plugin_string, ':');
if (params)
{
*params = 0;
++params;
}
if (g_path_is_absolute (plugin_string))
path = g_strdup (plugin_string);
else
path = g_strconcat (dpath, plugin_string, ".so", NULL);
module = mutter_plugin_manager_get_module (path);
if (module)
{
gboolean use_succeeded;
/*
* This dlopens the module and registers the plugin type with the
* GType system, if the module is not already loaded. When we
* create a plugin, the type system also calls g_type_module_use()
* to guarantee the module will not be unloaded during the plugin
* life time. Consequently we can unuse() the module again.
*/
use_succeeded = g_type_module_use (G_TYPE_MODULE (module));
if (use_succeeded)
{
MutterPluginPending *pending = g_new0 (MutterPluginPending, 1);
pending->module = module;
pending->path = g_strdup (path);
pending->params = g_strdup (params);
plugin_mgr->pending_plugin_modules =
g_list_prepend (plugin_mgr->pending_plugin_modules, pending);
}
}
else
g_warning ("Unable to load plugin module [%s]: %s",
path, g_module_error());
g_free (path);
g_free (plugin_string);
}
plugins = plugins->next;
}
if (fallback)
g_slist_free (fallback);
if (plugin_mgr->pending_plugin_modules != NULL)
{
meta_prefs_add_listener (prefs_changed_callback, plugin_mgr);
return TRUE;
}
return FALSE;
}
gboolean
mutter_plugin_manager_initialize (MutterPluginManager *plugin_mgr)
{
GList *iter;
for (iter = plugin_mgr->pending_plugin_modules; iter; iter = iter->next)
{
MutterPluginPending *pending = (MutterPluginPending*) iter->data;
MutterPlugin *p;
if ((p = mutter_plugin_load (plugin_mgr, pending->module, pending->params)))
{
plugin_mgr->plugins = g_list_prepend (plugin_mgr->plugins, p);
}
else
{
g_warning ("Plugin load for [%s] failed", pending->path);
}
g_type_module_unuse (G_TYPE_MODULE (pending->module));
g_free (pending->path);
g_free (pending->params);
g_free (pending);
}
g_list_free (plugin_mgr->pending_plugin_modules);
plugin_mgr->pending_plugin_modules = NULL;
return TRUE;
}
/*
* Reloads all plugins
*/
static gboolean
mutter_plugin_manager_reload (MutterPluginManager *plugin_mgr)
{
/* TODO -- brute force; should we build a list of plugins to load and list of
* plugins to unload? We are probably not going to have large numbers of
* plugins loaded at the same time, so it might not be worth it.
*/
mutter_plugin_manager_unload (plugin_mgr);
return mutter_plugin_manager_load (plugin_mgr);
}
MutterPluginManager *
mutter_plugin_manager_new (MetaScreen *screen)
{
MutterPluginManager *plugin_mgr;
if (!plugin_modules)
{
plugin_modules = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
NULL);
}
plugin_mgr = g_new0 (MutterPluginManager, 1);
plugin_mgr->screen = screen;
return plugin_mgr;
}
static void
mutter_plugin_manager_kill_effect (MutterPluginManager *plugin_mgr,
MutterWindow *actor,
unsigned long events)
{
GList *l = plugin_mgr->plugins;
while (l)
{
MutterPlugin *plugin = l->data;
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
if (!mutter_plugin_disabled (plugin)
&& (mutter_plugin_features (plugin) & events)
&& klass->kill_effect)
klass->kill_effect (plugin, actor, events);
l = l->next;
}
}
#define ALL_BUT_SWITCH \
MUTTER_PLUGIN_ALL_EFFECTS & \
~MUTTER_PLUGIN_SWITCH_WORKSPACE
/*
* Public method that the compositor hooks into for events that require
* no additional parameters.
*
* Returns TRUE if at least one of the plugins handled the event type (i.e.,
* if the return value is FALSE, there will be no subsequent call to the
* manager completed() callback, and the compositor must ensure that any
* appropriate post-effect cleanup is carried out.
*/
gboolean
mutter_plugin_manager_event_simple (MutterPluginManager *plugin_mgr,
MutterWindow *actor,
unsigned long event)
{
GList *l = plugin_mgr->plugins;
gboolean retval = FALSE;
while (l)
{
MutterPlugin *plugin = l->data;
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
if (!mutter_plugin_disabled (plugin) &&
(mutter_plugin_features (plugin) & event))
{
retval = TRUE;
switch (event)
{
case MUTTER_PLUGIN_MINIMIZE:
if (klass->minimize)
{
mutter_plugin_manager_kill_effect (
plugin_mgr,
actor,
ALL_BUT_SWITCH);
_mutter_plugin_effect_started (plugin);
klass->minimize (plugin, actor);
}
break;
case MUTTER_PLUGIN_MAP:
if (klass->map)
{
mutter_plugin_manager_kill_effect (
plugin_mgr,
actor,
ALL_BUT_SWITCH);
_mutter_plugin_effect_started (plugin);
klass->map (plugin, actor);
}
break;
case MUTTER_PLUGIN_DESTROY:
if (klass->destroy)
{
_mutter_plugin_effect_started (plugin);
klass->destroy (plugin, actor);
}
break;
default:
g_warning ("Incorrect handler called for event %lu", event);
}
}
l = l->next;
}
return retval;
}
/*
* The public method that the compositor hooks into for maximize and unmaximize
* events.
*
* Returns TRUE if at least one of the plugins handled the event type (i.e.,
* if the return value is FALSE, there will be no subsequent call to the
* manager completed() callback, and the compositor must ensure that any
* appropriate post-effect cleanup is carried out.
*/
gboolean
mutter_plugin_manager_event_maximize (MutterPluginManager *plugin_mgr,
MutterWindow *actor,
unsigned long event,
gint target_x,
gint target_y,
gint target_width,
gint target_height)
{
GList *l = plugin_mgr->plugins;
gboolean retval = FALSE;
while (l)
{
MutterPlugin *plugin = l->data;
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
if (!mutter_plugin_disabled (plugin) &&
(mutter_plugin_features (plugin) & event))
{
retval = TRUE;
switch (event)
{
case MUTTER_PLUGIN_MAXIMIZE:
if (klass->maximize)
{
mutter_plugin_manager_kill_effect (
plugin_mgr,
actor,
ALL_BUT_SWITCH);
_mutter_plugin_effect_started (plugin);
klass->maximize (plugin, actor,
target_x, target_y,
target_width, target_height);
}
break;
case MUTTER_PLUGIN_UNMAXIMIZE:
if (klass->unmaximize)
{
mutter_plugin_manager_kill_effect (
plugin_mgr,
actor,
ALL_BUT_SWITCH);
_mutter_plugin_effect_started (plugin);
klass->unmaximize (plugin, actor,
target_x, target_y,
target_width, target_height);
}
break;
default:
g_warning ("Incorrect handler called for event %lu", event);
}
}
l = l->next;
}
return retval;
}
/*
* The public method that the compositor hooks into for desktop switching.
*
* Returns TRUE if at least one of the plugins handled the event type (i.e.,
* if the return value is FALSE, there will be no subsequent call to the
* manager completed() callback, and the compositor must ensure that any
* appropriate post-effect cleanup is carried out.
*/
gboolean
mutter_plugin_manager_switch_workspace (MutterPluginManager *plugin_mgr,
const GList **actors,
gint from,
gint to,
MetaMotionDirection direction)
{
GList *l = plugin_mgr->plugins;
gboolean retval = FALSE;
while (l)
{
MutterPlugin *plugin = l->data;
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
if (!mutter_plugin_disabled (plugin) &&
(mutter_plugin_features (plugin) & MUTTER_PLUGIN_SWITCH_WORKSPACE) &&
(actors && *actors))
{
if (klass->switch_workspace)
{
retval = TRUE;
mutter_plugin_manager_kill_effect (
plugin_mgr,
MUTTER_WINDOW ((*actors)->data),
MUTTER_PLUGIN_SWITCH_WORKSPACE);
_mutter_plugin_effect_started (plugin);
klass->switch_workspace (plugin, actors, from, to, direction);
}
}
l = l->next;
}
return retval;
}
/*
* The public method that the compositor hooks into for desktop switching.
*
* Returns TRUE if at least one of the plugins handled the event type (i.e.,
* if the return value is FALSE, there will be no subsequent call to the
* manager completed() callback, and the compositor must ensure that any
* appropriate post-effect cleanup is carried out.
*/
gboolean
mutter_plugin_manager_xevent_filter (MutterPluginManager *plugin_mgr,
XEvent *xev)
{
GList *l;
if (!plugin_mgr)
return FALSE;
l = plugin_mgr->plugins;
while (l)
{
MutterPlugin *plugin = l->data;
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
if (klass->xevent_filter)
{
if (klass->xevent_filter (plugin, xev) == TRUE)
return TRUE;
}
l = l->next;
}
return FALSE;
}

View File

@@ -0,0 +1,63 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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 MUTTER_PLUGIN_MANAGER_H_
#define MUTTER_PLUGIN_MANAGER_H_
#include "types.h"
#include "screen.h"
#define MUTTER_PLUGIN_FROM_MANAGER_
#include "mutter-plugin.h"
#undef MUTTER_PLUGIN_FROM_MANAGER_
typedef struct MutterPluginManager MutterPluginManager;
MutterPluginManager * mutter_plugin_manager_new (MetaScreen *screen);
gboolean mutter_plugin_manager_load (MutterPluginManager *mgr);
gboolean mutter_plugin_manager_initialize (MutterPluginManager *plugin_mgr);
gboolean mutter_plugin_manager_event_simple (MutterPluginManager *mgr,
MutterWindow *actor,
unsigned long event);
gboolean mutter_plugin_manager_event_maximize (MutterPluginManager *mgr,
MutterWindow *actor,
unsigned long event,
gint target_x,
gint target_y,
gint target_width,
gint target_height);
void mutter_plugin_manager_update_workspaces (MutterPluginManager *mgr);
void mutter_plugin_manager_update_workspace (MutterPluginManager *mgr, MetaWorkspace *w);
gboolean mutter_plugin_manager_switch_workspace (MutterPluginManager *mgr,
const GList **actors,
gint from,
gint to,
MetaMotionDirection direction);
gboolean mutter_plugin_manager_xevent_filter (MutterPluginManager *mgr,
XEvent *xev);
#endif

View File

@@ -0,0 +1,484 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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 "mutter-plugin.h"
#include "screen.h"
#include "display.h"
#include <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/shape.h>
#include <clutter/x11/clutter-x11.h>
G_DEFINE_ABSTRACT_TYPE (MutterPlugin, mutter_plugin, G_TYPE_OBJECT);
#define MUTTER_PLUGIN_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_PLUGIN, MutterPluginPrivate))
enum
{
PROP_0,
PROP_SCREEN,
PROP_PARAMS,
PROP_FEATURES,
PROP_DISABLED,
PROP_DEBUG_MODE,
};
struct _MutterPluginPrivate
{
MetaScreen *screen;
gchar *params;
gulong features;
gint running;
gboolean disabled : 1;
gboolean debug : 1;
};
static void
mutter_plugin_dispose (GObject *object)
{
G_OBJECT_CLASS (mutter_plugin_parent_class)->dispose (object);
}
static void
mutter_plugin_finalize (GObject *object)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (object)->priv;
g_free (priv->params);
priv->params = NULL;
G_OBJECT_CLASS (mutter_plugin_parent_class)->finalize (object);
}
static void
mutter_plugin_parse_params (MutterPlugin *plugin)
{
char *p;
gulong features = 0;
MutterPluginPrivate *priv = plugin->priv;
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
/*
* Feature flags: identify events that the plugin can handle; a plugin can
* handle one or more events.
*/
if (klass->minimize)
features |= MUTTER_PLUGIN_MINIMIZE;
if (klass->maximize)
features |= MUTTER_PLUGIN_MAXIMIZE;
if (klass->unmaximize)
features |= MUTTER_PLUGIN_UNMAXIMIZE;
if (klass->map)
features |= MUTTER_PLUGIN_MAP;
if (klass->destroy)
features |= MUTTER_PLUGIN_DESTROY;
if (klass->switch_workspace)
features |= MUTTER_PLUGIN_SWITCH_WORKSPACE;
if (priv->params)
{
gboolean debug = FALSE;
if ((p = strstr (priv->params, "disable:")))
{
gchar *d = g_strdup (p+8);
p = strchr (d, ';');
if (p)
*p = 0;
if (strstr (d, "minimize"))
features &= ~ MUTTER_PLUGIN_MINIMIZE;
if (strstr (d, "maximize"))
features &= ~ MUTTER_PLUGIN_MAXIMIZE;
if (strstr (d, "unmaximize"))
features &= ~ MUTTER_PLUGIN_UNMAXIMIZE;
if (strstr (d, "map"))
features &= ~ MUTTER_PLUGIN_MAP;
if (strstr (d, "destroy"))
features &= ~ MUTTER_PLUGIN_DESTROY;
if (strstr (d, "switch-workspace"))
features &= ~MUTTER_PLUGIN_SWITCH_WORKSPACE;
g_free (d);
}
if (strstr (priv->params, "debug"))
debug = TRUE;
if (debug != priv->debug)
{
priv->debug = debug;
g_object_notify (G_OBJECT (plugin), "debug-mode");
}
}
if (features != priv->features)
{
priv->features = features;
g_object_notify (G_OBJECT (plugin), "features");
}
}
static void
mutter_plugin_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (object)->priv;
switch (prop_id)
{
case PROP_SCREEN:
priv->screen = g_value_get_object (value);
break;
case PROP_PARAMS:
priv->params = g_value_dup_string (value);
mutter_plugin_parse_params (MUTTER_PLUGIN (object));
break;
case PROP_DISABLED:
priv->disabled = g_value_get_boolean (value);
break;
case PROP_DEBUG_MODE:
priv->debug = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
mutter_plugin_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (object)->priv;
switch (prop_id)
{
case PROP_SCREEN:
g_value_set_object (value, priv->screen);
break;
case PROP_PARAMS:
g_value_set_string (value, priv->params);
break;
case PROP_DISABLED:
g_value_set_boolean (value, priv->disabled);
break;
case PROP_DEBUG_MODE:
g_value_set_boolean (value, priv->debug);
break;
case PROP_FEATURES:
g_value_set_ulong (value, priv->features);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
mutter_plugin_class_init (MutterPluginClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = mutter_plugin_finalize;
gobject_class->dispose = mutter_plugin_dispose;
gobject_class->set_property = mutter_plugin_set_property;
gobject_class->get_property = mutter_plugin_get_property;
g_object_class_install_property (gobject_class,
PROP_SCREEN,
g_param_spec_object ("screen",
"MetaScreen",
"MetaScreen",
META_TYPE_SCREEN,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class,
PROP_PARAMS,
g_param_spec_string ("params",
"Parameters",
"Plugin Parameters",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_FEATURES,
g_param_spec_ulong ("features",
"Features",
"Plugin Features",
0 , G_MAXULONG, 0,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_DISABLED,
g_param_spec_boolean ("disabled",
"Plugin disabled",
"Plugin disabled",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_DEBUG_MODE,
g_param_spec_boolean ("debug-mode",
"Debug Mode",
"Debug Mode",
FALSE,
G_PARAM_READABLE));
g_type_class_add_private (gobject_class, sizeof (MutterPluginPrivate));
}
static void
mutter_plugin_init (MutterPlugin *self)
{
MutterPluginPrivate *priv;
self->priv = priv = MUTTER_PLUGIN_GET_PRIVATE (self);
}
gulong
mutter_plugin_features (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return priv->features;
}
gboolean
mutter_plugin_disabled (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return priv->disabled;
}
gboolean
mutter_plugin_running (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return (priv->running > 0);
}
gboolean
mutter_plugin_debug_mode (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return priv->debug;
}
const MutterPluginInfo *
mutter_plugin_get_info (MutterPlugin *plugin)
{
MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin);
if (klass && klass->plugin_info)
return klass->plugin_info (plugin);
return NULL;
}
ClutterActor *
mutter_plugin_get_overlay_group (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return mutter_get_overlay_group_for_screen (priv->screen);
}
ClutterActor *
mutter_plugin_get_stage (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return mutter_get_stage_for_screen (priv->screen);
}
ClutterActor *
mutter_plugin_get_window_group (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return mutter_get_window_group_for_screen (priv->screen);
}
/**
* _mutter_plugin_effect_started:
* @plugin: the plugin
*
* Mark that an effect has started for the plugin. This is called
* internally by MutterPluginManager.
*/
void
_mutter_plugin_effect_started (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
priv->running++;
}
void
mutter_plugin_effect_completed (MutterPlugin *plugin,
MutterWindow *actor,
unsigned long event)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
if (priv->running-- < 0)
{
g_warning ("Error in running effect accounting, adjusting.");
priv->running = 0;
}
if (!actor)
{
const MutterPluginInfo *info;
const gchar *name = NULL;
if (plugin && (info = mutter_plugin_get_info (plugin)))
name = info->name;
g_warning ("Plugin [%s] passed NULL for actor!",
name ? name : "unknown");
}
mutter_window_effect_completed (actor, event);
}
void
mutter_plugin_query_screen_size (MutterPlugin *plugin,
int *width,
int *height)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
meta_screen_get_size (priv->screen, width, height);
}
void
mutter_plugin_set_stage_reactive (MutterPlugin *plugin,
gboolean reactive)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
if (reactive)
mutter_set_stage_input_region (screen, None);
else
mutter_empty_stage_input_region (screen);
}
void
mutter_plugin_set_stage_input_area (MutterPlugin *plugin,
gint x, gint y, gint width, gint height)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdpy = meta_display_get_xdisplay (display);
XRectangle rect;
XserverRegion region;
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
region = XFixesCreateRegion (xdpy, &rect, 1);
mutter_set_stage_input_region (screen, region);
XFixesDestroyRegion (xdpy, region);
}
void
mutter_plugin_set_stage_input_region (MutterPlugin *plugin,
XserverRegion region)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
mutter_set_stage_input_region (screen, region);
}
GList *
mutter_plugin_get_windows (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return mutter_get_windows (priv->screen);
}
Display *
mutter_plugin_get_xdisplay (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
MetaDisplay *display = meta_screen_get_display (priv->screen);
Display *xdpy = meta_display_get_xdisplay (display);
return xdpy;
}
/**
* mutter_plugin_get_screen:
* @plugin: a #MutterPlugin
*
* Gets the #MetaScreen corresponding to a plugin. Each plugin instance
* is associated with exactly one screen; if Metacity is managing
* multiple screens, multiple plugin instances will be created.
*
* Return value: (transfer none): the #MetaScreen for the plugin
*/
MetaScreen *
mutter_plugin_get_screen (MutterPlugin *plugin)
{
MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv;
return priv->screen;
}

View File

@@ -0,0 +1,428 @@
/*
* shaped texture
*
* An actor to draw a texture clipped to a list of rectangles
*
* Authored By Neil Roberts <neil@linux.intel.com>
*
* Copyright (C) 2008 Intel Corporation
*
* 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 "mutter-shaped-texture.h"
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
static void mutter_shaped_texture_dispose (GObject *object);
static void mutter_shaped_texture_finalize (GObject *object);
static void mutter_shaped_texture_paint (ClutterActor *actor);
static void mutter_shaped_texture_pick (ClutterActor *actor,
const ClutterColor *color);
static void mutter_shaped_texture_dirty_mask (MutterShapedTexture *stex);
#ifdef HAVE_GLX_TEXTURE_PIXMAP
G_DEFINE_TYPE (MutterShapedTexture, mutter_shaped_texture,
CLUTTER_GLX_TYPE_TEXTURE_PIXMAP);
#else /* HAVE_GLX_TEXTURE_PIXMAP */
G_DEFINE_TYPE (MutterShapedTexture, mutter_shaped_texture,
CLUTTER_X11_TYPE_TEXTURE_PIXMAP);
#endif /* HAVE_GLX_TEXTURE_PIXMAP */
#define MUTTER_SHAPED_TEXTURE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_SHAPED_TEXTURE, \
MutterShapedTexturePrivate))
struct _MutterShapedTexturePrivate
{
CoglHandle mask_texture;
CoglHandle material;
#if 1 /* see workaround comment in mutter_shaped_texture_paint */
CoglHandle material_workaround;
#endif
guint mask_width, mask_height;
GArray *rectangles;
};
static void
mutter_shaped_texture_class_init (MutterShapedTextureClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
gobject_class->dispose = mutter_shaped_texture_dispose;
gobject_class->finalize = mutter_shaped_texture_finalize;
actor_class->paint = mutter_shaped_texture_paint;
actor_class->pick = mutter_shaped_texture_pick;
g_type_class_add_private (klass, sizeof (MutterShapedTexturePrivate));
}
static void
mutter_shaped_texture_init (MutterShapedTexture *self)
{
MutterShapedTexturePrivate *priv;
priv = self->priv = MUTTER_SHAPED_TEXTURE_GET_PRIVATE (self);
priv->rectangles = g_array_new (FALSE, FALSE, sizeof (XRectangle));
priv->mask_texture = COGL_INVALID_HANDLE;
}
static void
mutter_shaped_texture_dispose (GObject *object)
{
MutterShapedTexture *self = (MutterShapedTexture *) object;
MutterShapedTexturePrivate *priv = self->priv;
mutter_shaped_texture_dirty_mask (self);
if (priv->material != COGL_INVALID_HANDLE)
{
cogl_material_unref (priv->material);
priv->material = COGL_INVALID_HANDLE;
}
#if 1 /* see comment in mutter_shaped_texture_paint */
if (priv->material_workaround != COGL_INVALID_HANDLE)
{
cogl_material_unref (priv->material_workaround);
priv->material_workaround = COGL_INVALID_HANDLE;
}
#endif
G_OBJECT_CLASS (mutter_shaped_texture_parent_class)->dispose (object);
}
static void
mutter_shaped_texture_finalize (GObject *object)
{
MutterShapedTexture *self = (MutterShapedTexture *) object;
MutterShapedTexturePrivate *priv = self->priv;
g_array_free (priv->rectangles, TRUE);
G_OBJECT_CLASS (mutter_shaped_texture_parent_class)->finalize (object);
}
static void
mutter_shaped_texture_dirty_mask (MutterShapedTexture *stex)
{
MutterShapedTexturePrivate *priv = stex->priv;
if (priv->mask_texture != COGL_INVALID_HANDLE)
{
GLuint mask_gl_tex;
GLenum mask_gl_target;
cogl_texture_get_gl_texture (priv->mask_texture,
&mask_gl_tex, &mask_gl_target);
if (mask_gl_target == CGL_TEXTURE_RECTANGLE_ARB)
glDeleteTextures (1, &mask_gl_tex);
cogl_texture_unref (priv->mask_texture);
priv->mask_texture = COGL_INVALID_HANDLE;
}
}
static void
mutter_shaped_texture_ensure_mask (MutterShapedTexture *stex)
{
MutterShapedTexturePrivate *priv = stex->priv;
CoglHandle paint_tex;
guint tex_width, tex_height;
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
if (paint_tex == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
/* If the mask texture we have was created for a different size then
recreate it */
if (priv->mask_texture != COGL_INVALID_HANDLE
&& (priv->mask_width != tex_width || priv->mask_height != tex_height))
mutter_shaped_texture_dirty_mask (stex);
/* If we don't have a mask texture yet then create one */
if (priv->mask_texture == COGL_INVALID_HANDLE)
{
guchar *mask_data;
const XRectangle *rect;
GLenum paint_gl_target;
/* Create data for an empty image */
mask_data = g_malloc0 (tex_width * tex_height);
/* Cut out a hole for each rectangle */
for (rect = (XRectangle *) priv->rectangles->data
+ priv->rectangles->len;
rect-- > (XRectangle *) priv->rectangles->data;)
{
gint x1 = rect->x, x2 = x1 + rect->width;
gint y1 = rect->y, y2 = y1 + rect->height;
guchar *p;
/* Clip the rectangle to the size of the texture */
x1 = CLAMP (x1, 0, (gint) tex_width - 1);
x2 = CLAMP (x2, x1, (gint) tex_width);
y1 = CLAMP (y1, 0, (gint) tex_height - 1);
y2 = CLAMP (y2, y1, (gint) tex_height);
/* Fill the rectangle */
for (p = mask_data + y1 * tex_width + x1;
y1 < y2;
y1++, p += tex_width)
memset (p, 255, x2 - x1);
}
cogl_texture_get_gl_texture (paint_tex, NULL, &paint_gl_target);
if (paint_gl_target == CGL_TEXTURE_RECTANGLE_ARB)
{
GLuint tex;
glGenTextures (1, &tex);
glBindTexture (CGL_TEXTURE_RECTANGLE_ARB, tex);
glPixelStorei (GL_UNPACK_ROW_LENGTH, tex_width);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glTexImage2D (CGL_TEXTURE_RECTANGLE_ARB, 0,
GL_ALPHA, tex_width, tex_height,
0, GL_ALPHA, GL_UNSIGNED_BYTE, mask_data);
priv->mask_texture
= cogl_texture_new_from_foreign (tex,
CGL_TEXTURE_RECTANGLE_ARB,
tex_width, tex_height,
0, 0,
COGL_PIXEL_FORMAT_A_8);
}
else
priv->mask_texture = cogl_texture_new_from_data (tex_width, tex_height,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_A_8,
COGL_PIXEL_FORMAT_ANY,
tex_width,
mask_data);
g_free (mask_data);
priv->mask_width = tex_width;
priv->mask_height = tex_height;
}
}
static void
mutter_shaped_texture_paint (ClutterActor *actor)
{
MutterShapedTexture *stex = (MutterShapedTexture *) actor;
MutterShapedTexturePrivate *priv = stex->priv;
CoglHandle paint_tex;
guint tex_width, tex_height;
ClutterActorBox alloc;
CoglHandle material;
#if 1 /* please see comment below about workaround */
guint depth;
#endif
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
clutter_actor_realize (CLUTTER_ACTOR (stex));
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
if (tex_width == 0 || tex_width == 0) /* no contents yet */
return;
/* If there are no rectangles fallback to the regular paint
method */
if (priv->rectangles->len < 1)
{
CLUTTER_ACTOR_CLASS (mutter_shaped_texture_parent_class)
->paint (actor);
return;
}
if (paint_tex == COGL_INVALID_HANDLE)
return;
mutter_shaped_texture_ensure_mask (stex);
if (priv->material == COGL_INVALID_HANDLE)
{
priv->material = cogl_material_new ();
cogl_material_set_layer_combine (priv->material, 1,
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
NULL);
}
material = priv->material;
#if 1
/* This was added as a workaround. It seems that with the intel
* drivers when multi-texturing using an RGB TFP texture, the
* texture is actually setup internally as an RGBA texture, where
* the alpha channel is mostly 0.0 so you only see a shimmer of the
* window. This workaround forcibly defines the alpha channel as
* 1.0. Maybe there is some clutter/cogl state that is interacting
* with this that is being overlooked, but for now this seems to
* work. */
g_object_get (stex, "pixmap-depth", &depth, NULL);
if (depth == 24)
{
if (priv->material_workaround == COGL_INVALID_HANDLE)
{
material = priv->material_workaround = cogl_material_new ();
cogl_material_set_layer_combine (material, 0,
"RGB = MODULATE (TEXTURE, PREVIOUS)"
"A = REPLACE (PREVIOUS)",
NULL);
cogl_material_set_layer_combine (material, 1,
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
NULL);
}
material = priv->material_workaround;
}
#endif
cogl_material_set_layer (material, 0, paint_tex);
cogl_material_set_layer (material, 1, priv->mask_texture);
{
CoglColor color;
guchar opacity = clutter_actor_get_paint_opacity (actor);
cogl_color_set_from_4ub (&color, opacity, opacity, opacity, opacity);
cogl_material_set_color (material, &color);
}
cogl_set_source (material);
clutter_actor_get_allocation_box (actor, &alloc);
cogl_rectangle (0, 0,
alloc.x2 - alloc.x1,
alloc.y2 - alloc.y1);
}
static void
mutter_shaped_texture_pick (ClutterActor *actor,
const ClutterColor *color)
{
MutterShapedTexture *stex = (MutterShapedTexture *) actor;
MutterShapedTexturePrivate *priv = stex->priv;
/* If there are no rectangles then use the regular pick */
if (priv->rectangles->len < 1)
CLUTTER_ACTOR_CLASS (mutter_shaped_texture_parent_class)
->pick (actor, color);
else if (clutter_actor_should_pick_paint (actor))
{
CoglHandle paint_tex;
ClutterActorBox alloc;
guint tex_width, tex_height;
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
if (paint_tex == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
if (tex_width == 0 || tex_width == 0) /* no contents yet */
return;
mutter_shaped_texture_ensure_mask (stex);
cogl_set_source_color4ub (color->red, color->green, color->blue,
color->alpha);
clutter_actor_get_allocation_box (actor, &alloc);
/* Paint the mask rectangle in the given color */
cogl_set_source_texture (priv->mask_texture);
cogl_rectangle_with_texture_coords (0, 0,
alloc.x2 - alloc.x1,
alloc.y2 - alloc.y1,
0, 0, 1, 1);
}
}
ClutterActor *
mutter_shaped_texture_new (void)
{
ClutterActor *self = g_object_new (MUTTER_TYPE_SHAPED_TEXTURE, NULL);
return self;
}
void
mutter_shaped_texture_clear_rectangles (MutterShapedTexture *stex)
{
MutterShapedTexturePrivate *priv;
g_return_if_fail (MUTTER_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
g_array_set_size (priv->rectangles, 0);
mutter_shaped_texture_dirty_mask (stex);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
void
mutter_shaped_texture_add_rectangle (MutterShapedTexture *stex,
const XRectangle *rect)
{
g_return_if_fail (MUTTER_IS_SHAPED_TEXTURE (stex));
mutter_shaped_texture_add_rectangles (stex, 1, rect);
}
void
mutter_shaped_texture_add_rectangles (MutterShapedTexture *stex,
size_t num_rects,
const XRectangle *rects)
{
MutterShapedTexturePrivate *priv;
g_return_if_fail (MUTTER_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
g_array_append_vals (priv->rectangles, rects, num_rects);
mutter_shaped_texture_dirty_mask (stex);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}

View File

@@ -0,0 +1,95 @@
/*
* shaped texture
*
* An actor to draw a texture clipped to a list of rectangles
*
* Authored By Neil Roberts <neil@linux.intel.com>
*
* Copyright (C) 2008 Intel Corporation
*
* 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 __MUTTER_SHAPED_TEXTURE_H__
#define __MUTTER_SHAPED_TEXTURE_H__
#include <clutter/clutter.h>
#ifdef HAVE_GLX_TEXTURE_PIXMAP
#include <clutter/glx/clutter-glx.h>
#endif /* HAVE_GLX_TEXTURE_PIXMAP */
G_BEGIN_DECLS
#define MUTTER_TYPE_SHAPED_TEXTURE \
(mutter_shaped_texture_get_type())
#define MUTTER_SHAPED_TEXTURE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
MUTTER_TYPE_SHAPED_TEXTURE, \
MutterShapedTexture))
#define MUTTER_SHAPED_TEXTURE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
MUTTER_TYPE_SHAPED_TEXTURE, \
MutterShapedTextureClass))
#define MUTTER_IS_SHAPED_TEXTURE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
MUTTER_TYPE_SHAPED_TEXTURE))
#define MUTTER_IS_SHAPED_TEXTURE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
MUTTER_TYPE_SHAPED_TEXTURE))
#define MUTTER_SHAPED_TEXTURE_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
MUTTER_TYPE_SHAPED_TEXTURE, \
MutterShapedTextureClass))
typedef struct _MutterShapedTexture MutterShapedTexture;
typedef struct _MutterShapedTextureClass MutterShapedTextureClass;
typedef struct _MutterShapedTexturePrivate MutterShapedTexturePrivate;
struct _MutterShapedTextureClass
{
#ifdef HAVE_GLX_TEXTURE_PIXMAP
ClutterGLXTexturePixmapClass parent_class;
#else
ClutterX11TexturePixmapClass parent_class;
#endif
};
struct _MutterShapedTexture
{
#ifdef HAVE_GLX_TEXTURE_PIXMAP
ClutterGLXTexturePixmap parent;
#else
ClutterX11TexturePixmap parent;
#endif
MutterShapedTexturePrivate *priv;
};
GType mutter_shaped_texture_get_type (void) G_GNUC_CONST;
ClutterActor *mutter_shaped_texture_new (void);
void mutter_shaped_texture_clear_rectangles (MutterShapedTexture *stex);
void mutter_shaped_texture_add_rectangle (MutterShapedTexture *stex,
const XRectangle *rect);
void mutter_shaped_texture_add_rectangles (MutterShapedTexture *stex,
size_t num_rects,
const XRectangle *rects);
G_END_DECLS
#endif /* __MUTTER_SHAPED_TEXTURE_H__ */

View File

@@ -0,0 +1,22 @@
pkglibdir=@MUTTER_PLUGIN_DIR@
if WITH_CLUTTER
INCLUDES=@MUTTER_CFLAGS@ -I $(top_srcdir)/src/include -DMUTTER_LIBEXECDIR=\"$(libexecdir)\" -DHOST_ALIAS=\"@HOST_ALIAS@\" -DMUTTER_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" -DMUTTER_PKGDATADIR=\"$(pkgdatadir)\" -DMUTTER_DATADIR=\"$(datadir)\" -DG_LOG_DOMAIN=\"mutter\" -DSN_API_NOT_YET_FROZEN=1 -DMUTTER_MAJOR_VERSION=$(MUTTER_MAJOR_VERSION) -DMUTTER_MINOR_VERSION=$(MUTTER_MINOR_VERSION) -DMUTTER_MICRO_VERSION=$(MUTTER_MICRO_VERSION) -DMUTTER_PLUGIN_API_VERSION=$(MUTTER_PLUGIN_API_VERSION) -DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\"
default_la_CFLAGS = -fPIC
default_la_SOURCES = default.c
default_la_LDFLAGS = -module -avoid-version -no-undefined
default_la_LIBADD = @CLUTTER_LIBS@
pkglib_LTLIBRARIES = default.la
# post-install hook to remove the .la and .a files we are not interested in
# (There is no way to stop libtool generating static libs locally, and we
# cannot do this globally because of libmutter-private.so).
install-exec-hook:
-rm $(DESTDIR)$(pkglibdir)/*.a
-rm $(DESTDIR)$(pkglibdir)/*.la
endif

View File

@@ -0,0 +1,41 @@
Plugins implement effects associated with WM events, such as window map,
minimizing, maximizing, unmaximizing, destruction and workspace switching. The
plugin API is documented in src/include/compositor-clutter-plugin.h; in
addition the simple plugin can be used as a reference implementation.
The API is intended to be generic, exposing no implementation details of the WM
to the plugins; this will facilitate reuse without modification with another WM
(there are plans to use the same plugin API with Matchbox 2).
Multiple plugins can implement the same effect and be loaded at the same time;
however, stacking arbitrary effects in this way might not work as expected;
this is particularly true of more complex effects, such as those for workspace
switching.
Plugins are installed in ${prefix}/lib/metacity/plugins/clutter; from there the
WM will load plugins listed in the clutter_plugins key in the Metacity gconf
general preferences group. Each entry in preferences has the format
'name: optional parameters'
where 'name' is the name of the library without the .so suffix.
As noted above, additional parameters can be passed to the plugin via the
preference key. In such case, the plugin name is immediately followed by a
colon, separating it from the parameters. Two common parameters should be
handled by all plugins:
'debug' indicates that the plugin is run in a debug mode (what exactly that
means is left to the plugin to determine).
'disable' parameter indicates which effects within the plugin should be
disabled; the format of the disable parameter is
'disable: effect1[, effect2];'
where effect1, etc., matches the effects listed in the
compositor-clutter-plugin.h file (currently one of 'map', 'destroy',
'maximize', 'unmaximize', 'switch-workspace'). Example 'disable:
minimize, maximize;'.

View File

@@ -21,8 +21,7 @@
* 02111-1307, USA.
*/
#include <meta/meta-plugin.h>
#include <meta/window.h>
#include "mutter-plugin.h"
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
@@ -40,78 +39,71 @@
#define ACTOR_DATA_KEY "MCCP-Default-actor-data"
#define META_TYPE_DEFAULT_PLUGIN (meta_default_plugin_get_type ())
#define META_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPlugin))
#define META_DEFAULT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPluginClass))
#define META_IS_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_DEFAULT_PLUGIN_TYPE))
#define META_IS_DEFAULT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_DEFAULT_PLUGIN))
#define META_DEFAULT_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPluginClass))
#define MUTTER_TYPE_DEFAULT_PLUGIN (mutter_default_plugin_get_type ())
#define MUTTER_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUTTER_TYPE_DEFAULT_PLUGIN, MutterDefaultPlugin))
#define MUTTER_DEFAULT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MUTTER_TYPE_DEFAULT_PLUGIN, MutterDefaultPluginClass))
#define MUTTER_IS_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUTTER_DEFAULT_PLUGIN_TYPE))
#define MUTTER_IS_DEFAULT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MUTTER_TYPE_DEFAULT_PLUGIN))
#define MUTTER_DEFAULT_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MUTTER_TYPE_DEFAULT_PLUGIN, MutterDefaultPluginClass))
#define META_DEFAULT_PLUGIN_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPluginPrivate))
#define MUTTER_DEFAULT_PLUGIN_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_DEFAULT_PLUGIN, MutterDefaultPluginPrivate))
typedef struct _MetaDefaultPlugin MetaDefaultPlugin;
typedef struct _MetaDefaultPluginClass MetaDefaultPluginClass;
typedef struct _MetaDefaultPluginPrivate MetaDefaultPluginPrivate;
typedef struct _MutterDefaultPlugin MutterDefaultPlugin;
typedef struct _MutterDefaultPluginClass MutterDefaultPluginClass;
typedef struct _MutterDefaultPluginPrivate MutterDefaultPluginPrivate;
struct _MetaDefaultPlugin
struct _MutterDefaultPlugin
{
MetaPlugin parent;
MutterPlugin parent;
MetaDefaultPluginPrivate *priv;
MutterDefaultPluginPrivate *priv;
};
struct _MetaDefaultPluginClass
struct _MutterDefaultPluginClass
{
MetaPluginClass parent_class;
MutterPluginClass parent_class;
};
static GQuark actor_data_quark = 0;
static void minimize (MetaPlugin *plugin,
MetaWindowActor *actor);
static void map (MetaPlugin *plugin,
MetaWindowActor *actor);
static void destroy (MetaPlugin *plugin,
MetaWindowActor *actor);
static void maximize (MetaPlugin *plugin,
MetaWindowActor *actor,
gint x,
gint y,
gint width,
gint height);
static void unmaximize (MetaPlugin *plugin,
MetaWindowActor *actor,
gint x,
gint y,
gint width,
gint height);
static void minimize (MutterPlugin *plugin,
MutterWindow *actor);
static void map (MutterPlugin *plugin,
MutterWindow *actor);
static void destroy (MutterPlugin *plugin,
MutterWindow *actor);
static void maximize (MutterPlugin *plugin,
MutterWindow *actor,
gint x, gint y, gint width, gint height);
static void unmaximize (MutterPlugin *plugin,
MutterWindow *actor,
gint x, gint y, gint width, gint height);
static void switch_workspace (MetaPlugin *plugin,
gint from,
gint to,
MetaMotionDirection direction);
static void switch_workspace (MutterPlugin *plugin,
const GList **actors, gint from, gint to,
MetaMotionDirection direction);
static void kill_window_effects (MetaPlugin *plugin,
MetaWindowActor *actor);
static void kill_switch_workspace (MetaPlugin *plugin);
static void kill_effect (MutterPlugin *plugin,
MutterWindow *actor, gulong event);
static const MetaPluginInfo * plugin_info (MetaPlugin *plugin);
static const MutterPluginInfo * plugin_info (MutterPlugin *plugin);
META_PLUGIN_DECLARE(MetaDefaultPlugin, meta_default_plugin);
MUTTER_PLUGIN_DECLARE(MutterDefaultPlugin, mutter_default_plugin);
/*
* Plugin private data that we store in the .plugin_private member.
*/
struct _MetaDefaultPluginPrivate
struct _MutterDefaultPluginPrivate
{
/* Valid only when switch_workspace effect is in progress */
ClutterTimeline *tml_switch_workspace1;
ClutterTimeline *tml_switch_workspace2;
GList **actors;
ClutterActor *desktop1;
ClutterActor *desktop2;
MetaPluginInfo info;
MutterPluginInfo info;
gboolean debug_mode : 1;
};
@@ -136,26 +128,26 @@ typedef struct _ActorPrivate
typedef struct
{
ClutterActor *actor;
MetaPlugin *plugin;
MutterPlugin *plugin;
} EffectCompleteData;
static void
meta_default_plugin_dispose (GObject *object)
mutter_default_plugin_dispose (GObject *object)
{
/* MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (object)->priv;
/* MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (object)->priv;
*/
G_OBJECT_CLASS (meta_default_plugin_parent_class)->dispose (object);
G_OBJECT_CLASS (mutter_default_plugin_parent_class)->dispose (object);
}
static void
meta_default_plugin_finalize (GObject *object)
mutter_default_plugin_finalize (GObject *object)
{
G_OBJECT_CLASS (meta_default_plugin_parent_class)->finalize (object);
G_OBJECT_CLASS (mutter_default_plugin_parent_class)->finalize (object);
}
static void
meta_default_plugin_set_property (GObject *object,
mutter_default_plugin_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
@@ -169,7 +161,7 @@ meta_default_plugin_set_property (GObject *object,
}
static void
meta_default_plugin_get_property (GObject *object,
mutter_default_plugin_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
@@ -183,9 +175,10 @@ meta_default_plugin_get_property (GObject *object,
}
static void
start (MetaPlugin *plugin)
mutter_default_plugin_constructed (GObject *object)
{
MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
MutterPlugin *plugin = MUTTER_PLUGIN (object);
MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (object)->priv;
guint destroy_timeout = DESTROY_TIMEOUT;
guint minimize_timeout = MINIMIZE_TIMEOUT;
@@ -193,7 +186,7 @@ start (MetaPlugin *plugin)
guint map_timeout = MAP_TIMEOUT;
guint switch_timeout = SWITCH_TIMEOUT;
if (meta_plugin_debug_mode (plugin))
if (mutter_plugin_debug_mode (plugin))
{
g_debug ("Plugin %s: Entering debug mode.", priv->info.name);
@@ -208,39 +201,39 @@ start (MetaPlugin *plugin)
map_timeout *= 2;
switch_timeout *= 2;
}
}
static void
meta_default_plugin_class_init (MetaDefaultPluginClass *klass)
mutter_default_plugin_class_init (MutterDefaultPluginClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
MetaPluginClass *plugin_class = META_PLUGIN_CLASS (klass);
MutterPluginClass *plugin_class = MUTTER_PLUGIN_CLASS (klass);
gobject_class->finalize = meta_default_plugin_finalize;
gobject_class->dispose = meta_default_plugin_dispose;
gobject_class->set_property = meta_default_plugin_set_property;
gobject_class->get_property = meta_default_plugin_get_property;
gobject_class->finalize = mutter_default_plugin_finalize;
gobject_class->dispose = mutter_default_plugin_dispose;
gobject_class->constructed = mutter_default_plugin_constructed;
gobject_class->set_property = mutter_default_plugin_set_property;
gobject_class->get_property = mutter_default_plugin_get_property;
plugin_class->start = start;
plugin_class->map = map;
plugin_class->minimize = minimize;
plugin_class->maximize = maximize;
plugin_class->unmaximize = unmaximize;
plugin_class->destroy = destroy;
plugin_class->switch_workspace = switch_workspace;
plugin_class->kill_effect = kill_effect;
plugin_class->plugin_info = plugin_info;
plugin_class->kill_window_effects = kill_window_effects;
plugin_class->kill_switch_workspace = kill_switch_workspace;
g_type_class_add_private (gobject_class, sizeof (MetaDefaultPluginPrivate));
g_type_class_add_private (gobject_class, sizeof (MutterDefaultPluginPrivate));
}
static void
meta_default_plugin_init (MetaDefaultPlugin *self)
mutter_default_plugin_init (MutterDefaultPlugin *self)
{
MetaDefaultPluginPrivate *priv;
MutterDefaultPluginPrivate *priv;
self->priv = priv = META_DEFAULT_PLUGIN_GET_PRIVATE (self);
self->priv = priv = MUTTER_DEFAULT_PLUGIN_GET_PRIVATE (self);
priv->info.name = "Default Effects";
priv->info.version = "0.1";
@@ -260,7 +253,7 @@ free_actor_private (gpointer data)
}
static ActorPrivate *
get_actor_private (MetaWindowActor *actor)
get_actor_private (MutterWindow *actor)
{
ActorPrivate *priv = g_object_get_qdata (G_OBJECT (actor), actor_data_quark);
@@ -279,18 +272,26 @@ get_actor_private (MetaWindowActor *actor)
return priv;
}
typedef struct SwitchWorkspaceData
{
MutterPlugin *plugin;
const GList **actors;
} SwitchWorkspaceData;
static void
on_switch_workspace_effect_complete (ClutterTimeline *timeline, gpointer data)
{
MetaPlugin *plugin = META_PLUGIN (data);
MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
GList *l = meta_plugin_get_window_actors (plugin);
SwitchWorkspaceData *sw_data = data;
MutterPlugin *plugin = sw_data->plugin;
MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv;
GList *l = *((GList**)sw_data->actors);
MutterWindow *actor_for_cb = l->data;
while (l)
{
ClutterActor *a = l->data;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (a);
ActorPrivate *apriv = get_actor_private (window_actor);
MutterWindow *mc_window = MUTTER_WINDOW (a);
ActorPrivate *apriv = get_actor_private (mc_window);
if (apriv->orig_parent)
{
@@ -304,30 +305,40 @@ on_switch_workspace_effect_complete (ClutterTimeline *timeline, gpointer data)
clutter_actor_destroy (priv->desktop1);
clutter_actor_destroy (priv->desktop2);
priv->actors = NULL;
priv->tml_switch_workspace1 = NULL;
priv->tml_switch_workspace2 = NULL;
priv->desktop1 = NULL;
priv->desktop2 = NULL;
meta_plugin_switch_workspace_completed (plugin);
g_free (data);
mutter_plugin_effect_completed (plugin, actor_for_cb,
MUTTER_PLUGIN_SWITCH_WORKSPACE);
}
static void
switch_workspace (MetaPlugin *plugin,
gint from, gint to,
switch_workspace (MutterPlugin *plugin,
const GList **actors, gint from, gint to,
MetaMotionDirection direction)
{
MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
MutterDefaultPluginPrivate *priv = MUTTER_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 = mutter_plugin_get_screen (plugin);
SwitchWorkspaceData *sw_data = g_new (SwitchWorkspaceData, 1);
ClutterAnimation *animation;
stage = meta_plugin_get_stage (plugin);
sw_data->plugin = plugin;
sw_data->actors = actors;
meta_plugin_query_screen_size (plugin,
stage = mutter_plugin_get_stage (plugin);
mutter_plugin_query_screen_size (plugin,
&screen_width,
&screen_height);
clutter_actor_set_anchor_point (workspace1,
@@ -344,29 +355,32 @@ switch_workspace (MetaPlugin *plugin,
if (from == to)
{
meta_plugin_switch_workspace_completed (plugin);
mutter_plugin_effect_completed (plugin, NULL,
MUTTER_PLUGIN_SWITCH_WORKSPACE);
return;
}
l = g_list_last (meta_plugin_get_window_actors (plugin));
n_workspaces = meta_screen_get_n_workspaces (screen);
l = g_list_last (*((GList**) actors));
while (l)
{
MetaWindowActor *window_actor = l->data;
ActorPrivate *apriv = get_actor_private (window_actor);
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
gint win_workspace;
MutterWindow *mc_window = l->data;
ActorPrivate *apriv = get_actor_private (mc_window);
ClutterActor *window = CLUTTER_ACTOR (mc_window);
gint win_workspace;
win_workspace = meta_window_actor_get_workspace (window_actor);
win_workspace = mutter_window_get_workspace (mc_window);
if (win_workspace == to || win_workspace == from)
{
apriv->orig_parent = clutter_actor_get_parent (actor);
apriv->orig_parent = clutter_actor_get_parent (window);
clutter_actor_reparent (actor,
clutter_actor_reparent (window,
win_workspace == to ? workspace1 : workspace0);
clutter_actor_show_all (actor);
clutter_actor_raise_top (actor);
clutter_actor_show_all (window);
clutter_actor_raise_top (window);
}
else if (win_workspace < 0)
{
@@ -376,13 +390,14 @@ switch_workspace (MetaPlugin *plugin,
else
{
/* Window on some other desktop */
clutter_actor_hide (actor);
clutter_actor_hide (window);
apriv->orig_parent = NULL;
}
l = l->prev;
}
priv->actors = (GList **)actors;
priv->desktop1 = workspace0;
priv->desktop2 = workspace1;
@@ -395,7 +410,7 @@ switch_workspace (MetaPlugin *plugin,
g_signal_connect (priv->tml_switch_workspace1,
"completed",
G_CALLBACK (on_switch_workspace_effect_complete),
plugin);
sw_data);
animation = clutter_actor_animate (workspace1, CLUTTER_EASE_IN_SINE,
SWITCH_TIMEOUT,
@@ -417,11 +432,11 @@ on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
* Must reverse the effect of the effect; must hide it first to ensure
* that the restoration will not be visible.
*/
MetaPlugin *plugin = data->plugin;
MutterPlugin *plugin = data->plugin;
ActorPrivate *apriv;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor);
MutterWindow *mc_window = MUTTER_WINDOW (data->actor);
apriv = get_actor_private (META_WINDOW_ACTOR (data->actor));
apriv = get_actor_private (MUTTER_WINDOW (data->actor));
apriv->tml_minimize = NULL;
clutter_actor_hide (data->actor);
@@ -433,7 +448,8 @@ on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
CLUTTER_GRAVITY_NORTH_WEST);
/* Now notify the manager that we are done with this effect */
meta_plugin_minimize_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_MINIMIZE);
g_free (data);
}
@@ -443,20 +459,18 @@ on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
* completion).
*/
static void
minimize (MetaPlugin *plugin, MetaWindowActor *window_actor)
minimize (MutterPlugin *plugin, MutterWindow *mc_window)
{
MetaWindowType type;
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
MetaCompWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (mc_window);
type = mutter_window_get_window_type (mc_window);
type = meta_window_get_window_type (meta_window);
if (type == META_WINDOW_NORMAL)
if (type == META_COMP_WINDOW_NORMAL)
{
ClutterAnimation *animation;
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
ActorPrivate *apriv = get_actor_private (mc_window);
apriv->is_minimized = TRUE;
@@ -478,7 +492,8 @@ minimize (MetaPlugin *plugin, MetaWindowActor *window_actor)
}
else
meta_plugin_minimize_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_MINIMIZE);
}
/*
@@ -491,9 +506,9 @@ on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
/*
* Must reverse the effect of the effect.
*/
MetaPlugin *plugin = data->plugin;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor);
ActorPrivate *apriv = get_actor_private (window_actor);
MutterPlugin * plugin = data->plugin;
MutterWindow *mc_window = MUTTER_WINDOW (data->actor);
ActorPrivate *apriv = get_actor_private (mc_window);
apriv->tml_maximize = NULL;
@@ -503,7 +518,8 @@ on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
CLUTTER_GRAVITY_NORTH_WEST);
/* Now notify the manager that we are done with this effect */
meta_plugin_maximize_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_MAXIMIZE);
g_free (data);
}
@@ -517,26 +533,25 @@ on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
* (Something like a sound would be more appropriate.)
*/
static void
maximize (MetaPlugin *plugin,
MetaWindowActor *window_actor,
maximize (MutterPlugin *plugin,
MutterWindow *mc_window,
gint end_x, gint end_y, gint end_width, gint end_height)
{
MetaWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
MetaCompWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (mc_window);
gdouble scale_x = 1.0;
gdouble scale_y = 1.0;
gfloat anchor_x = 0;
gfloat anchor_y = 0;
type = meta_window_get_window_type (meta_window);
type = mutter_window_get_window_type (mc_window);
if (type == META_WINDOW_NORMAL)
if (type == META_COMP_WINDOW_NORMAL)
{
ClutterAnimation *animation;
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
ActorPrivate *apriv = get_actor_private (mc_window);
gfloat width, height;
gfloat x, y;
@@ -574,7 +589,8 @@ maximize (MetaPlugin *plugin,
return;
}
meta_plugin_maximize_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_MAXIMIZE);
}
/*
@@ -583,22 +599,22 @@ maximize (MetaPlugin *plugin,
* (Just a skeleton code.)
*/
static void
unmaximize (MetaPlugin *plugin,
MetaWindowActor *window_actor,
unmaximize (MutterPlugin *plugin,
MutterWindow *mc_window,
gint end_x, gint end_y, gint end_width, gint end_height)
{
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
MetaWindowType type = meta_window_get_window_type (meta_window);
MetaCompWindowType type = mutter_window_get_window_type (mc_window);
if (type == META_WINDOW_NORMAL)
if (type == META_COMP_WINDOW_NORMAL)
{
ActorPrivate *apriv = get_actor_private (window_actor);
ActorPrivate *apriv = get_actor_private (mc_window);
apriv->is_maximized = FALSE;
}
/* Do this conditionally, if the effect requires completion callback. */
meta_plugin_unmaximize_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_UNMAXIMIZE);
}
static void
@@ -607,9 +623,9 @@ on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
/*
* Must reverse the effect of the effect.
*/
MetaPlugin *plugin = data->plugin;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor);
ActorPrivate *apriv = get_actor_private (window_actor);
MutterPlugin *plugin = data->plugin;
MutterWindow *mc_window = MUTTER_WINDOW (data->actor);
ActorPrivate *apriv = get_actor_private (mc_window);
apriv->tml_map = NULL;
@@ -617,7 +633,7 @@ on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
CLUTTER_GRAVITY_NORTH_WEST);
/* Now notify the manager that we are done with this effect */
meta_plugin_map_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_MAP);
g_free (data);
}
@@ -627,19 +643,18 @@ on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
* completion).
*/
static void
map (MetaPlugin *plugin, MetaWindowActor *window_actor)
map (MutterPlugin *plugin, MutterWindow *mc_window)
{
MetaWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
MetaCompWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (mc_window);
type = meta_window_get_window_type (meta_window);
type = mutter_window_get_window_type (mc_window);
if (type == META_WINDOW_NORMAL)
if (type == META_COMP_WINDOW_NORMAL)
{
ClutterAnimation *animation;
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
ActorPrivate *apriv = get_actor_private (mc_window);
clutter_actor_move_anchor_point_from_gravity (actor,
CLUTTER_GRAVITY_CENTER);
@@ -664,7 +679,8 @@ map (MetaPlugin *plugin, MetaWindowActor *window_actor)
}
else
meta_plugin_map_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_MAP);
}
/*
@@ -674,32 +690,32 @@ map (MetaPlugin *plugin, MetaWindowActor *window_actor)
static void
on_destroy_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
{
MetaPlugin *plugin = data->plugin;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor);
ActorPrivate *apriv = get_actor_private (window_actor);
MutterPlugin *plugin = data->plugin;
MutterWindow *mc_window = MUTTER_WINDOW (data->actor);
ActorPrivate *apriv = get_actor_private (mc_window);
apriv->tml_destroy = NULL;
meta_plugin_destroy_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_DESTROY);
}
/*
* Simple TV-out like effect.
*/
static void
destroy (MetaPlugin *plugin, MetaWindowActor *window_actor)
destroy (MutterPlugin *plugin, MutterWindow *mc_window)
{
MetaWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
MetaCompWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (mc_window);
type = meta_window_get_window_type (meta_window);
type = mutter_window_get_window_type (mc_window);
if (type == META_WINDOW_NORMAL)
if (type == META_COMP_WINDOW_NORMAL)
{
ClutterAnimation *animation;
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
ActorPrivate *apriv = get_actor_private (mc_window);
clutter_actor_move_anchor_point_from_gravity (actor,
CLUTTER_GRAVITY_CENTER);
@@ -718,59 +734,64 @@ destroy (MetaPlugin *plugin, MetaWindowActor *window_actor)
data);
}
else
meta_plugin_destroy_completed (plugin, window_actor);
mutter_plugin_effect_completed (plugin, mc_window,
MUTTER_PLUGIN_DESTROY);
}
static void
kill_switch_workspace (MetaPlugin *plugin)
{
MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
if (priv->tml_switch_workspace1)
{
clutter_timeline_stop (priv->tml_switch_workspace1);
clutter_timeline_stop (priv->tml_switch_workspace2);
g_signal_emit_by_name (priv->tml_switch_workspace1, "completed", NULL);
}
}
static void
kill_window_effects (MetaPlugin *plugin,
MetaWindowActor *window_actor)
kill_effect (MutterPlugin *plugin, MutterWindow *mc_window, gulong event)
{
ActorPrivate *apriv;
apriv = get_actor_private (window_actor);
if (event & MUTTER_PLUGIN_SWITCH_WORKSPACE)
{
MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv;
if (apriv->tml_minimize)
if (priv->tml_switch_workspace1)
{
clutter_timeline_stop (priv->tml_switch_workspace1);
clutter_timeline_stop (priv->tml_switch_workspace2);
g_signal_emit_by_name (priv->tml_switch_workspace1, "completed", NULL);
}
if (!(event & ~MUTTER_PLUGIN_SWITCH_WORKSPACE))
{
/* Workspace switch only, nothing more to do */
return;
}
}
apriv = get_actor_private (mc_window);
if ((event & MUTTER_PLUGIN_MINIMIZE) && apriv->tml_minimize)
{
clutter_timeline_stop (apriv->tml_minimize);
g_signal_emit_by_name (apriv->tml_minimize, "completed", NULL);
}
if (apriv->tml_maximize)
if ((event & MUTTER_PLUGIN_MAXIMIZE) && apriv->tml_maximize)
{
clutter_timeline_stop (apriv->tml_maximize);
g_signal_emit_by_name (apriv->tml_maximize, "completed", NULL);
}
if (apriv->tml_map)
if ((event & MUTTER_PLUGIN_MAP) && apriv->tml_map)
{
clutter_timeline_stop (apriv->tml_map);
g_signal_emit_by_name (apriv->tml_map, "completed", NULL);
}
if (apriv->tml_destroy)
if ((event & MUTTER_PLUGIN_DESTROY) && apriv->tml_destroy)
{
clutter_timeline_stop (apriv->tml_destroy);
g_signal_emit_by_name (apriv->tml_destroy, "completed", NULL);
}
}
static const MetaPluginInfo *
plugin_info (MetaPlugin *plugin)
static const MutterPluginInfo *
plugin_info (MutterPlugin *plugin)
{
MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv;
return &priv->info;
}

View File

@@ -0,0 +1,610 @@
/* 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;
};
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_material_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;
/* 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_material_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;
}

View File

@@ -0,0 +1,81 @@
/* 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);
G_END_DECLS
#endif /* _HAVE_TIDY_TEXTURE_FRAME_H */

View File

@@ -1,18 +0,0 @@
pkglibdir=@MUTTER_PLUGIN_DIR@
INCLUDES=@MUTTER_CFLAGS@ -I $(top_srcdir)/src -DMUTTER_LIBEXECDIR=\"$(libexecdir)\" -DHOST_ALIAS=\"@HOST_ALIAS@\" -DMUTTER_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" -DMUTTER_PKGDATADIR=\"$(pkgdatadir)\" -DMUTTER_DATADIR=\"$(datadir)\" -DG_LOG_DOMAIN=\"mutter\" -DSN_API_NOT_YET_FROZEN=1 -DMUTTER_MAJOR_VERSION=$(MUTTER_MAJOR_VERSION) -DMUTTER_MINOR_VERSION=$(MUTTER_MINOR_VERSION) -DMUTTER_MICRO_VERSION=$(MUTTER_MICRO_VERSION) -DMUTTER_PLUGIN_API_VERSION=$(MUTTER_PLUGIN_API_VERSION) -DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\"
default_la_CFLAGS = -fPIC
default_la_SOURCES = default.c
default_la_LDFLAGS = -module -avoid-version -no-undefined
default_la_LIBADD = @CLUTTER_LIBS@
pkglib_LTLIBRARIES = default.la
# post-install hook to remove the .la and .a files we are not interested in
# (There is no way to stop libtool generating static libs locally, and we
# cannot do this globally because of libmutter-private.so).
install-exec-hook:
-rm $(DESTDIR)$(pkglibdir)/*.a
-rm $(DESTDIR)$(pkglibdir)/*.la

View File

@@ -1,330 +0,0 @@
/* -*- 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;
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);
last_x = extents.x;
for (meta_region_iterator_init (&iter, region);
!meta_region_iterator_at_end (&iter);
meta_region_iterator_next (&iter))
{
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

@@ -1,76 +0,0 @@
/* -*- 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,243 +0,0 @@
/* -*- 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);
if (!keyboard)
return best_keycode;
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;
}

138
src/core/alttabhandler.c Normal file
View File

@@ -0,0 +1,138 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity Alt-Tab abstraction */
/*
* Copyright (C) 2009 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 "alttabhandlerdefault.h"
#include "screen-private.h"
static GType handler_type = G_TYPE_INVALID;
GType meta_alt_tab_handler_default_get_type (void);
void
meta_alt_tab_handler_register (GType type)
{
handler_type = type;
}
MetaAltTabHandler *
meta_alt_tab_handler_new (MetaScreen *screen,
gboolean immediate)
{
if (handler_type == G_TYPE_INVALID)
handler_type = meta_alt_tab_handler_default_get_type ();
return g_object_new (handler_type,
"screen", screen,
"immediate", immediate,
NULL);
}
static void meta_alt_tab_handler_class_init (GObjectClass *object_class);
GType
meta_alt_tab_handler_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
const GTypeInfo type_info =
{
sizeof (MetaAltTabHandlerInterface), /* class_size */
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc)meta_alt_tab_handler_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
0,
0, /* n_preallocs */
NULL
};
GType g_define_type_id =
g_type_register_static (G_TYPE_INTERFACE, "MetaAltTabHandler",
&type_info, 0);
g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
static void
meta_alt_tab_handler_class_init (GObjectClass *object_class)
{
g_object_interface_install_property (object_class,
g_param_spec_object ("screen",
"Screen",
"MetaScreen this is the switcher for",
META_TYPE_SCREEN,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
g_object_interface_install_property (object_class,
g_param_spec_boolean ("immediate",
"Immediate mode",
"Whether or not to select windows immediately",
FALSE,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
}
void
meta_alt_tab_handler_add_window (MetaAltTabHandler *handler,
MetaWindow *window)
{
META_ALT_TAB_HANDLER_GET_INTERFACE (handler)->add_window (handler, window);
}
void
meta_alt_tab_handler_show (MetaAltTabHandler *handler,
MetaWindow *initial_selection)
{
META_ALT_TAB_HANDLER_GET_INTERFACE (handler)->show (handler,
initial_selection);
}
void
meta_alt_tab_handler_destroy (MetaAltTabHandler *handler)
{
META_ALT_TAB_HANDLER_GET_INTERFACE (handler)->destroy (handler);
}
void
meta_alt_tab_handler_forward (MetaAltTabHandler *handler)
{
META_ALT_TAB_HANDLER_GET_INTERFACE (handler)->forward (handler);
}
void
meta_alt_tab_handler_backward (MetaAltTabHandler *handler)
{
META_ALT_TAB_HANDLER_GET_INTERFACE (handler)->backward (handler);
}
MetaWindow *
meta_alt_tab_handler_get_selected (MetaAltTabHandler *handler)
{
return META_ALT_TAB_HANDLER_GET_INTERFACE (handler)->get_selected (handler);
}

View File

@@ -0,0 +1,223 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity Alt-Tab abstraction: default implementation */
/*
* Copyright (C) 2009 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 "alttabhandlerdefault.h"
#include "frame-private.h"
#include "window-private.h"
static void meta_alt_tab_handler_default_interface_init (MetaAltTabHandlerInterface *handler_iface);
G_DEFINE_TYPE_WITH_CODE (MetaAltTabHandlerDefault, meta_alt_tab_handler_default, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (META_TYPE_ALT_TAB_HANDLER,
meta_alt_tab_handler_default_interface_init))
enum {
PROP_SCREEN = 1,
PROP_IMMEDIATE
};
static void
meta_alt_tab_handler_default_init (MetaAltTabHandlerDefault *hd)
{
hd->entries = g_array_new (FALSE, FALSE, sizeof (MetaTabEntry));
}
static void
meta_alt_tab_handler_default_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (object);
switch (prop_id)
{
case PROP_SCREEN:
hd->screen = g_value_get_object (value);
break;
case PROP_IMMEDIATE:
hd->immediate_mode = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_alt_tab_handler_default_finalize (GObject *object)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (object);
g_array_free (hd->entries, TRUE);
if (hd->tab_popup)
meta_ui_tab_popup_free (hd->tab_popup);
G_OBJECT_CLASS (meta_alt_tab_handler_default_parent_class)->finalize (object);
}
static void
meta_alt_tab_handler_default_add_window (MetaAltTabHandler *handler,
MetaWindow *window)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (handler);
MetaTabEntry entry;
MetaRectangle r;
entry.key = (MetaTabEntryKey) window;
entry.title = window->title;
entry.icon = window->icon;
entry.blank = FALSE;
entry.hidden = !meta_window_showing_on_its_workspace (window);
entry.demands_attention = window->wm_state_demands_attention;
if (hd->immediate_mode || !entry.hidden ||
!meta_window_get_icon_geometry (window, &r))
meta_window_get_outer_rect (window, &r);
entry.rect = r;
/* Find inside of highlight rectangle to be used when window is
* outlined for tabbing. This should be the size of the
* east/west frame, and the size of the south frame, on those
* sides. On the top it should be the size of the south frame
* edge.
*/
#define OUTLINE_WIDTH 5
/* Top side */
if (!entry.hidden &&
window->frame && window->frame->bottom_height > 0 &&
window->frame->child_y >= window->frame->bottom_height)
entry.inner_rect.y = window->frame->bottom_height;
else
entry.inner_rect.y = OUTLINE_WIDTH;
/* Bottom side */
if (!entry.hidden &&
window->frame && window->frame->bottom_height != 0)
entry.inner_rect.height = r.height
- entry.inner_rect.y - window->frame->bottom_height;
else
entry.inner_rect.height = r.height
- entry.inner_rect.y - OUTLINE_WIDTH;
/* Left side */
if (!entry.hidden && window->frame && window->frame->child_x != 0)
entry.inner_rect.x = window->frame->child_x;
else
entry.inner_rect.x = OUTLINE_WIDTH;
/* Right side */
if (!entry.hidden &&
window->frame && window->frame->right_width != 0)
entry.inner_rect.width = r.width
- entry.inner_rect.x - window->frame->right_width;
else
entry.inner_rect.width = r.width
- entry.inner_rect.x - OUTLINE_WIDTH;
g_array_append_val (hd->entries, entry);
}
static void
meta_alt_tab_handler_default_show (MetaAltTabHandler *handler,
MetaWindow *initial_selection)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (handler);
if (hd->tab_popup)
return;
hd->tab_popup = meta_ui_tab_popup_new ((MetaTabEntry *)hd->entries->data,
hd->screen->number,
hd->entries->len,
5, /* FIXME */
TRUE);
meta_ui_tab_popup_select (hd->tab_popup, (MetaTabEntryKey) initial_selection);
meta_ui_tab_popup_set_showing (hd->tab_popup, !hd->immediate_mode);
}
static void
meta_alt_tab_handler_default_destroy (MetaAltTabHandler *handler)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (handler);
if (hd->tab_popup)
{
meta_ui_tab_popup_free (hd->tab_popup);
hd->tab_popup = NULL;
}
}
static void
meta_alt_tab_handler_default_forward (MetaAltTabHandler *handler)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (handler);
if (hd->tab_popup)
meta_ui_tab_popup_forward (hd->tab_popup);
}
static void
meta_alt_tab_handler_default_backward (MetaAltTabHandler *handler)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (handler);
if (hd->tab_popup)
meta_ui_tab_popup_backward (hd->tab_popup);
}
static MetaWindow *
meta_alt_tab_handler_default_get_selected (MetaAltTabHandler *handler)
{
MetaAltTabHandlerDefault *hd = META_ALT_TAB_HANDLER_DEFAULT (handler);
if (hd->tab_popup)
return (MetaWindow *)meta_ui_tab_popup_get_selected (hd->tab_popup);
else
return NULL;
}
static void
meta_alt_tab_handler_default_class_init (MetaAltTabHandlerDefaultClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = meta_alt_tab_handler_default_set_property;
object_class->finalize = meta_alt_tab_handler_default_finalize;
g_object_class_override_property (object_class, PROP_SCREEN, "screen");
g_object_class_override_property (object_class, PROP_IMMEDIATE, "immediate");
}
static void
meta_alt_tab_handler_default_interface_init (MetaAltTabHandlerInterface *handler_iface)
{
handler_iface->add_window = meta_alt_tab_handler_default_add_window;
handler_iface->show = meta_alt_tab_handler_default_show;
handler_iface->destroy = meta_alt_tab_handler_default_destroy;
handler_iface->forward = meta_alt_tab_handler_default_forward;
handler_iface->backward = meta_alt_tab_handler_default_backward;
handler_iface->get_selected = meta_alt_tab_handler_default_get_selected;
}

View File

@@ -51,10 +51,7 @@
#include <config.h>
#include "bell.h"
#include "screen-private.h"
#include <meta/prefs.h>
#ifdef HAVE_LIBCANBERRA
#include <canberra-gtk.h>
#endif
#include "prefs.h"
/**
* Flashes one entire screen. This is done by making a window the size of the
@@ -149,7 +146,7 @@ bell_flash_screen (MetaDisplay *display,
#ifdef HAVE_XKB
static void
bell_flash_fullscreen (MetaDisplay *display,
XkbAnyEvent *xkb_ev)
XkbAnyEvent *xkb_ev)
{
XkbBellNotifyEvent *xkb_bell_ev = (XkbBellNotifyEvent *) xkb_ev;
MetaScreen *screen;
@@ -159,12 +156,7 @@ bell_flash_fullscreen (MetaDisplay *display,
{
screen = meta_display_screen_for_xwindow (display, xkb_bell_ev->window);
if (screen)
{
if (display->compositor)
meta_compositor_flash_screen (display->compositor, screen);
else
bell_flash_screen (display, screen);
}
bell_flash_screen (display, screen);
}
else
{
@@ -172,10 +164,7 @@ bell_flash_fullscreen (MetaDisplay *display,
while (screen_list)
{
screen = (MetaScreen *) screen_list->data;
if (display->compositor)
meta_compositor_flash_screen (display->compositor, screen);
else
bell_flash_screen (display, screen);
bell_flash_screen (display, screen);
screen_list = screen_list->next;
}
}
@@ -239,18 +228,18 @@ bell_flash_window_frame (MetaWindow *window)
*/
static void
bell_flash_frame (MetaDisplay *display,
XkbAnyEvent *xkb_ev)
XkbAnyEvent *xkb_ev)
{
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
MetaWindow *window;
g_assert (xkb_ev->xkb_type == XkbBellNotify);
window = meta_display_lookup_x_window (display, xkb_bell_event->window);
if (!window && (display->focus_window))
if (!window && (display->focus_window) && (display->focus_window->frame))
{
window = display->focus_window;
}
if (window && window->frame)
if (window)
{
bell_flash_window_frame (window);
}
@@ -296,48 +285,6 @@ meta_bell_notify (MetaDisplay *display,
/* flash something */
if (meta_prefs_get_visual_bell ())
bell_visual_notify (display, xkb_ev);
#ifdef HAVE_LIBCANBERRA
if (meta_prefs_bell_is_audible ())
{
ca_proplist *p;
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent*) xkb_ev;
MetaWindow *window;
int res;
ca_proplist_create (&p);
ca_proplist_sets (p, CA_PROP_EVENT_ID, "bell-window-system");
ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION, _("Bell event"));
ca_proplist_sets (p, CA_PROP_CANBERRA_CACHE_CONTROL, "permanent");
window = meta_display_lookup_x_window (display, xkb_bell_event->window);
if (!window && (display->focus_window) && (display->focus_window->frame))
window = display->focus_window;
if (window)
{
ca_proplist_sets (p, CA_PROP_WINDOW_NAME, window->title);
ca_proplist_setf (p, CA_PROP_WINDOW_X11_XID, "%lu", (unsigned long)window->xwindow);
ca_proplist_sets (p, CA_PROP_APPLICATION_NAME, window->res_name);
ca_proplist_setf (p, CA_PROP_APPLICATION_PROCESS_ID, "%d", window->net_wm_pid);
}
/* First, we try to play a real sound ... */
res = ca_context_play_full (ca_gtk_context_get (), 1, p, NULL, NULL);
ca_proplist_destroy (p);
if (res != CA_SUCCESS && res != CA_ERROR_DISABLED)
{
/* ...and in case that failed we use the classic X11 bell. */
XkbForceDeviceBell (display->xdisplay,
xkb_bell_event->device,
xkb_bell_event->bell_class,
xkb_bell_event->bell_id,
xkb_bell_event->percent);
}
}
#endif /* HAVE_LIBCANBERRA */
}
#endif /* HAVE_XKB */
@@ -345,19 +292,11 @@ void
meta_bell_set_audible (MetaDisplay *display, gboolean audible)
{
#ifdef HAVE_XKB
#ifdef HAVE_LIBCANBERRA
/* When we are playing sounds using libcanberra support, we handle the
* bell whether its an audible bell or a visible bell */
gboolean enable_system_bell = FALSE;
#else
gboolean enable_system_bell = audible;
#endif /* HAVE_LIBCANBERRA */
XkbChangeEnabledControls (display->xdisplay,
XkbUseCoreKbd,
XkbAudibleBellMask,
enable_system_bell ? XkbAudibleBellMask : 0);
#endif /* HAVE_XKB */
XkbUseCoreKbd,
XkbAudibleBellMask,
audible ? XkbAudibleBellMask : 0);
#endif
}
gboolean
@@ -384,7 +323,11 @@ meta_bell_init (MetaDisplay *display)
XkbUseCoreKbd,
XkbBellNotifyMask,
XkbBellNotifyMask);
meta_bell_set_audible (display, meta_prefs_bell_is_audible ());
XkbChangeEnabledControls (display->xdisplay,
XkbUseCoreKbd,
XkbAudibleBellMask,
meta_prefs_bell_is_audible ()
? XkbAudibleBellMask : 0);
if (visual_bell_auto_reset) {
XkbSetAutoResetControls (display->xdisplay,
XkbAudibleBellMask,

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